@expressivecss/expressive 0.4.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 (68) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +4 -9
  3. package/dist/css/expressive.css +2309 -948
  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 +643 -804
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +643 -804
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +11 -11
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +643 -804
  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 +11 -11
  18. package/dist/types/components/index.d.ts +3 -5
  19. package/dist/types/components/{dropdown.d.ts → menu.d.ts} +38 -37
  20. package/dist/types/components/navigationRail.d.ts +53 -0
  21. package/dist/types/components/range.d.ts +3 -0
  22. package/dist/types/components/registry.d.ts +7 -15
  23. package/dist/types/components/select.d.ts +12 -12
  24. package/dist/types/components/{toasts.d.ts → snackbar.d.ts} +28 -25
  25. package/dist/types/index.d.ts +3 -1
  26. package/package.json +3 -2
  27. package/src/sass/README.md +13 -11
  28. package/src/sass/abstracts/_breakpoints.scss +14 -3
  29. package/src/sass/abstracts/_mixins.scss +3 -3
  30. package/src/sass/abstracts/_variables.scss +27 -2
  31. package/src/sass/base/_global.scss +1 -1
  32. package/src/sass/base/_grid.scss +66 -116
  33. package/src/sass/base/_index.scss +1 -1
  34. package/src/sass/components/_badges.scss +76 -61
  35. package/src/sass/components/_bottom-sheet.scss +137 -0
  36. package/src/sass/components/_cards.scss +4 -4
  37. package/src/sass/components/_chips.scss +6 -5
  38. package/src/sass/components/_dialog.scss +268 -0
  39. package/src/sass/components/_index.scss +8 -7
  40. package/src/sass/components/_list.scss +253 -0
  41. package/src/sass/components/_menu.scss +341 -0
  42. package/src/sass/components/_navbar.scss +65 -117
  43. package/src/sass/components/_navigation-bar.scss +165 -0
  44. package/src/sass/components/_navigation-rail.scss +308 -0
  45. package/src/sass/components/_page-footer.scss +7 -3
  46. package/src/sass/components/_side-sheet.scss +193 -0
  47. package/src/sass/components/_sidenav.scss +78 -49
  48. package/src/sass/components/{_toast.scss → _snackbar.scss} +35 -34
  49. package/src/sass/components/_tabs.scss +1 -27
  50. package/src/sass/components/_toolbar.scss +91 -25
  51. package/src/sass/components/_tooltip.scss +1 -1
  52. package/src/sass/components/forms/_fieldset.scss +1 -1
  53. package/src/sass/components/forms/_input-fields.scss +3 -3
  54. package/src/sass/components/forms/_range.scss +423 -98
  55. package/src/sass/components/forms/_select.scss +19 -17
  56. package/src/sass/tokens/_reference.scss +37 -13
  57. package/src/sass/tokens/_theme.scss +5 -13
  58. package/src/sass/utilities/_colors.scss +16 -74
  59. package/src/sass/utilities/_visibility.scss +8 -0
  60. package/dist/types/components/collapsible.d.ts +0 -79
  61. package/dist/types/components/pushpin.d.ts +0 -51
  62. package/dist/types/components/tapTarget.d.ts +0 -57
  63. package/src/sass/components/_collapsible.scss +0 -179
  64. package/src/sass/components/_collection.scss +0 -180
  65. package/src/sass/components/_dropdown.scss +0 -225
  66. package/src/sass/components/_modal.scss +0 -190
  67. package/src/sass/components/_pushpin.scss +0 -11
  68. package/src/sass/components/_tapTarget.scss +0 -187
@@ -22,28 +22,28 @@ var Expressive = (() => {
22
22
  __export(index_exports, {
23
23
  AutoInit: () => AutoInit,
24
24
  Autocomplete: () => Autocomplete,
25
+ BottomSheets: () => BottomSheets,
25
26
  Cards: () => Cards,
26
27
  Carousel: () => Carousel,
27
28
  CharacterCounter: () => CharacterCounter,
28
29
  Chips: () => Chips,
29
- Collapsible: () => Collapsible,
30
30
  Datepicker: () => Datepicker,
31
31
  Dialogs: () => Dialogs,
32
- Dropdown: () => Dropdown,
33
32
  FloatingActionButton: () => FloatingActionButton,
34
33
  FormSelect: () => FormSelect,
35
34
  Forms: () => Forms,
36
35
  Lightbox: () => Lightbox,
36
+ Menu: () => Menu,
37
+ NavigationRail: () => NavigationRail,
37
38
  Parallax: () => Parallax,
38
- Pushpin: () => Pushpin,
39
39
  Range: () => Range,
40
40
  ScrollSpy: () => ScrollSpy,
41
+ SideSheets: () => SideSheets,
41
42
  Sidenav: () => Sidenav,
42
43
  Slider: () => Slider,
44
+ Snackbar: () => Snackbar,
43
45
  Tabs: () => Tabs,
44
- TapTarget: () => TapTarget,
45
46
  Timepicker: () => Timepicker,
46
- Toast: () => Toast,
47
47
  Tooltip: () => Tooltip,
48
48
  Waves: () => Waves,
49
49
  version: () => version
@@ -567,13 +567,13 @@ var Expressive = (() => {
567
567
  }
568
568
  };
569
569
 
570
- // src/ts/components/dropdown.ts
570
+ // src/ts/components/menu.ts
571
571
  var _defaults2 = {
572
572
  alignment: "left",
573
573
  autoFocus: true,
574
574
  constrainWidth: true,
575
575
  container: null,
576
- coverTrigger: true,
576
+ coverTrigger: false,
577
577
  closeOnClick: true,
578
578
  hover: false,
579
579
  inDuration: 150,
@@ -584,9 +584,9 @@ var Expressive = (() => {
584
584
  onCloseEnd: null,
585
585
  onItemClick: null
586
586
  };
587
- var _Dropdown = class _Dropdown extends Component {
587
+ var _Menu = class _Menu extends Component {
588
588
  constructor(el, options) {
589
- super(el, options, _Dropdown);
589
+ super(el, options, _Menu);
590
590
  this._handleClick = (e) => {
591
591
  e.preventDefault();
592
592
  if (this.isOpen) {
@@ -604,22 +604,22 @@ var Expressive = (() => {
604
604
  this.close();
605
605
  return;
606
606
  }
607
- const leaveToDropdownContent = !!(this.dropdownEl && toEl && this.dropdownEl.contains(toEl));
608
- let leaveToActiveDropdownTrigger = false;
609
- const closestTrigger = toEl.closest(".dropdown-trigger");
610
- if (closestTrigger && !!closestTrigger["Expressive_Dropdown"] && closestTrigger["Expressive_Dropdown"].isOpen) {
611
- 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;
612
612
  }
613
- if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) {
613
+ if (!leaveToActiveMenuTrigger && !leaveToMenuContent) {
614
614
  this.close();
615
615
  }
616
616
  };
617
617
  this._handleDocumentClick = (e) => {
618
618
  const target = e.target;
619
619
  if (this._isSubmenuTriggerClick(target)) return;
620
- if (this.options.closeOnClick && this.dropdownEl?.contains(target) && !this.isTouchMoving) {
620
+ if (this.options.closeOnClick && this.menuEl?.contains(target) && !this.isTouchMoving) {
621
621
  this.close();
622
- } else if (!this.dropdownEl?.contains(target)) {
622
+ } else if (!this.menuEl?.contains(target)) {
623
623
  setTimeout(() => {
624
624
  if (this.isOpen) {
625
625
  this.close();
@@ -637,11 +637,11 @@ var Expressive = (() => {
637
637
  };
638
638
  this._handleDocumentTouchmove = (e) => {
639
639
  const target = e.target;
640
- if (this.dropdownEl?.contains(target)) {
640
+ if (this.menuEl?.contains(target)) {
641
641
  this.isTouchMoving = true;
642
642
  }
643
643
  };
644
- this._handleDropdownClick = (e) => {
644
+ this._handleMenuClick = (e) => {
645
645
  const target = e.target;
646
646
  const li = target.closest("li");
647
647
  if (li && this._isSubmenuTriggerClick(target)) {
@@ -658,11 +658,11 @@ var Expressive = (() => {
658
658
  const target = e.target;
659
659
  if (!(target instanceof Element)) return;
660
660
  const li = target.closest("li");
661
- if (li?.querySelector(":scope > menu") && this.dropdownEl?.contains(li)) {
661
+ if (li?.querySelector(":scope > menu") && this.menuEl?.contains(li)) {
662
662
  this._alignSubmenu(li);
663
663
  }
664
664
  };
665
- this._handleDropdownKeydown = (e) => {
665
+ this._handleMenuKeydown = (e) => {
666
666
  const arrowUpOrDown = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key);
667
667
  if (Utils.keys.TAB.includes(e.key)) {
668
668
  e.preventDefault();
@@ -689,7 +689,7 @@ var Expressive = (() => {
689
689
  } else if (arrowUpOrDown && this.isOpen) {
690
690
  e.preventDefault();
691
691
  const direction = Utils.keys.ARROW_DOWN.includes(e.key) ? 1 : -1;
692
- const list = this._containingSubmenu(e) ?? this.dropdownEl;
692
+ const list = this._containingSubmenu(e) ?? this.menuEl;
693
693
  let newFocusedIndex = this.focusedIndex;
694
694
  let hasFoundNewIndex = false;
695
695
  do {
@@ -714,7 +714,7 @@ var Expressive = (() => {
714
714
  this._toggleSubmenu(li);
715
715
  return;
716
716
  }
717
- const focusedElement = li ?? this.dropdownEl.children[this.focusedIndex];
717
+ const focusedElement = li ?? this.menuEl.children[this.focusedIndex];
718
718
  const activatableElement = focusedElement?.querySelector("a, button");
719
719
  if (!!activatableElement) {
720
720
  activatableElement.click();
@@ -723,7 +723,7 @@ var Expressive = (() => {
723
723
  }
724
724
  } else if (Utils.keys.ESC.includes(e.key) && this.isOpen) {
725
725
  e.preventDefault();
726
- const openSub = this.dropdownEl.querySelector("li.open");
726
+ const openSub = this.menuEl.querySelector("li.open");
727
727
  if (openSub) {
728
728
  openSub.classList.remove("open", "submenu-start");
729
729
  this._syncSubmenuAria(openSub, false);
@@ -744,7 +744,7 @@ var Expressive = (() => {
744
744
  if (isLetter && !specialKeys.includes(e.key)) {
745
745
  this.filterQuery.push(keyText);
746
746
  const string = this.filterQuery.join("");
747
- const list = this._containingSubmenu(e) ?? this.dropdownEl;
747
+ const list = this._containingSubmenu(e) ?? this.menuEl;
748
748
  const newOptionEl = Array.from(list.querySelectorAll(":scope > li")).find(
749
749
  (el) => el.textContent.trim().toLowerCase().indexOf(string) === 0
750
750
  );
@@ -765,7 +765,7 @@ var Expressive = (() => {
765
765
  this.filterQuery = [];
766
766
  };
767
767
  /**
768
- * Open dropdown.
768
+ * Open menu.
769
769
  */
770
770
  this.open = () => {
771
771
  if (this.isOpen) return;
@@ -773,15 +773,15 @@ var Expressive = (() => {
773
773
  if (typeof this.options.onOpenStart === "function") {
774
774
  this.options.onOpenStart.call(this, this.el);
775
775
  }
776
- this._resetDropdownStyles();
777
- this.dropdownEl.style.display = "block";
778
- this._placeDropdown();
776
+ this._resetMenuStyles();
777
+ this.menuEl.style.display = "block";
778
+ this._placeMenu();
779
779
  this._animateIn();
780
780
  setTimeout(() => this._setupTemporaryEventHandlers(), 0);
781
781
  this.el.ariaExpanded = "true";
782
782
  };
783
783
  /**
784
- * Close dropdown.
784
+ * Close menu.
785
785
  */
786
786
  this.close = () => {
787
787
  if (!this.isOpen) return;
@@ -799,20 +799,20 @@ var Expressive = (() => {
799
799
  this.el.ariaExpanded = "false";
800
800
  };
801
801
  /**
802
- * 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.
803
803
  */
804
804
  this.recalculateDimensions = () => {
805
805
  if (this.isOpen) {
806
- this._resetDropdownPositioningStyles();
807
- this._placeDropdown();
806
+ this._resetMenuPositioningStyles();
807
+ this._placeMenu();
808
808
  }
809
809
  };
810
- this.el["Expressive_Dropdown"] = this;
811
- _Dropdown._dropdowns.push(this);
810
+ this.el["Expressive_Menu"] = this;
811
+ _Menu._menus.push(this);
812
812
  this.id = Utils.getIdFromTrigger(el);
813
- this.dropdownEl = document.getElementById(this.id);
813
+ this.menuEl = document.getElementById(this.id);
814
814
  this.options = {
815
- ..._Dropdown.defaults,
815
+ ..._Menu.defaults,
816
816
  ...options
817
817
  };
818
818
  this.isOpen = false;
@@ -821,8 +821,8 @@ var Expressive = (() => {
821
821
  this.focusedIndex = -1;
822
822
  this.filterQuery = [];
823
823
  this.el.ariaExpanded = "false";
824
- this._moveDropdownToElement();
825
- this._makeDropdownFocusable();
824
+ this._moveMenuToElement();
825
+ this._makeMenuFocusable();
826
826
  this._setupSubmenus();
827
827
  this._setupEventHandlers();
828
828
  }
@@ -830,47 +830,47 @@ var Expressive = (() => {
830
830
  return _defaults2;
831
831
  }
832
832
  /**
833
- * Initializes instances of Dropdown.
833
+ * Initializes instances of Menu.
834
834
  * @param els HTML elements.
835
835
  * @param options Component options.
836
836
  */
837
837
  static init(els, options = {}) {
838
- return super.init(els, options, _Dropdown);
838
+ return super.init(els, options, _Menu);
839
839
  }
840
840
  static getInstance(el) {
841
- return el["Expressive_Dropdown"];
841
+ return el["Expressive_Menu"];
842
842
  }
843
843
  destroy() {
844
844
  clearTimeout(this.filterTimeout);
845
- this._resetDropdownStyles();
845
+ this._resetMenuStyles();
846
846
  this._removeEventHandlers();
847
847
  this._removeTemporaryEventHandlers();
848
- const index = _Dropdown._dropdowns.indexOf(this);
849
- if (index >= 0) _Dropdown._dropdowns.splice(index, 1);
850
- 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;
851
851
  }
852
852
  _setupEventHandlers() {
853
853
  this.el.addEventListener("keydown", this._handleTriggerKeydown);
854
- this.dropdownEl?.addEventListener("click", this._handleDropdownClick);
855
- if (this.dropdownEl?.querySelector(":scope > li > menu")) {
856
- this.dropdownEl.addEventListener("mouseover", this._handleSubmenuAlign);
854
+ this.menuEl?.addEventListener("click", this._handleMenuClick);
855
+ if (this.menuEl?.querySelector(":scope > li > menu")) {
856
+ this.menuEl.addEventListener("mouseover", this._handleSubmenuAlign);
857
857
  }
858
858
  if (this.options.hover) {
859
859
  this.el.addEventListener("mouseenter", this._handleMouseEnter);
860
860
  this.el.addEventListener("mouseleave", this._handleMouseLeave);
861
- this.dropdownEl.addEventListener("mouseleave", this._handleMouseLeave);
861
+ this.menuEl.addEventListener("mouseleave", this._handleMouseLeave);
862
862
  } else {
863
863
  this.el.addEventListener("click", this._handleClick);
864
864
  }
865
865
  }
866
866
  _removeEventHandlers() {
867
867
  this.el.removeEventListener("keydown", this._handleTriggerKeydown);
868
- this.dropdownEl?.removeEventListener("click", this._handleDropdownClick);
869
- this.dropdownEl?.removeEventListener("mouseover", this._handleSubmenuAlign);
868
+ this.menuEl?.removeEventListener("click", this._handleMenuClick);
869
+ this.menuEl?.removeEventListener("mouseover", this._handleSubmenuAlign);
870
870
  if (this.options.hover) {
871
871
  this.el.removeEventListener("mouseenter", this._handleMouseEnter);
872
872
  this.el.removeEventListener("mouseleave", this._handleMouseLeave);
873
- this.dropdownEl?.removeEventListener("mouseleave", this._handleMouseLeave);
873
+ this.menuEl?.removeEventListener("mouseleave", this._handleMouseLeave);
874
874
  } else {
875
875
  this.el.removeEventListener("click", this._handleClick);
876
876
  }
@@ -878,25 +878,25 @@ var Expressive = (() => {
878
878
  _setupTemporaryEventHandlers() {
879
879
  document.body.addEventListener("click", this._handleDocumentClick);
880
880
  document.body.addEventListener("touchmove", this._handleDocumentTouchmove, { passive: true });
881
- this.dropdownEl?.addEventListener("keydown", this._handleDropdownKeydown);
881
+ this.menuEl?.addEventListener("keydown", this._handleMenuKeydown);
882
882
  window.addEventListener("resize", this._handleWindowResize);
883
883
  }
884
884
  _removeTemporaryEventHandlers() {
885
885
  document.body.removeEventListener("click", this._handleDocumentClick);
886
886
  document.body.removeEventListener("touchmove", this._handleDocumentTouchmove);
887
- this.dropdownEl?.removeEventListener("keydown", this._handleDropdownKeydown);
887
+ this.menuEl?.removeEventListener("keydown", this._handleMenuKeydown);
888
888
  window.removeEventListener("resize", this._handleWindowResize);
889
889
  }
890
890
  _isSubmenuTriggerClick(target) {
891
- if (!this.dropdownEl) return false;
891
+ if (!this.menuEl) return false;
892
892
  const li = target.closest("li");
893
- if (!li || !this.dropdownEl.contains(li)) return false;
893
+ if (!li || !this.menuEl.contains(li)) return false;
894
894
  const submenu = li.querySelector(":scope > menu");
895
895
  if (!submenu) return false;
896
896
  return !submenu.contains(target);
897
897
  }
898
898
  _setupSubmenus() {
899
- this.dropdownEl?.querySelectorAll("li").forEach((li) => {
899
+ this.menuEl?.querySelectorAll("li").forEach((li) => {
900
900
  if (!li.querySelector(":scope > menu")) return;
901
901
  const trigger = li.querySelector(":scope > a, :scope > button, :scope > span") ?? li;
902
902
  trigger.setAttribute("aria-haspopup", "menu");
@@ -922,15 +922,12 @@ var Expressive = (() => {
922
922
  _alignSubmenu(li) {
923
923
  const menu = li.querySelector(":scope > menu");
924
924
  if (!menu) return;
925
- const wasHidden = getComputedStyle(menu).display === "none";
926
- if (wasHidden) menu.style.display = "block";
927
925
  li.classList.remove("submenu-start");
928
926
  const rect = menu.getBoundingClientRect();
929
927
  if (rect.right > window.innerWidth - 8) li.classList.add("submenu-start");
930
- if (wasHidden) menu.style.display = "";
931
928
  }
932
929
  _closeSubmenus() {
933
- this.dropdownEl?.querySelectorAll("li.open").forEach((li) => {
930
+ this.menuEl?.querySelectorAll("li.open").forEach((li) => {
934
931
  li.classList.remove("open", "submenu-start");
935
932
  this._syncSubmenuAria(li, false);
936
933
  });
@@ -939,46 +936,46 @@ var Expressive = (() => {
939
936
  const target = e.target;
940
937
  if (!(target instanceof Element)) return null;
941
938
  const submenu = target.closest("li > menu");
942
- if (submenu instanceof HTMLElement && this.dropdownEl?.contains(submenu)) return submenu;
939
+ if (submenu instanceof HTMLElement && this.menuEl?.contains(submenu)) return submenu;
943
940
  return null;
944
941
  }
945
942
  _focusedRow(e) {
946
943
  const target = e.target;
947
944
  if (!(target instanceof Element)) return null;
948
945
  const li = target.closest("li");
949
- if (li instanceof HTMLElement && this.dropdownEl?.contains(li)) return li;
946
+ if (li instanceof HTMLElement && this.menuEl?.contains(li)) return li;
950
947
  return null;
951
948
  }
952
- _resetDropdownStyles() {
953
- this.dropdownEl.style.display = "";
954
- this._resetDropdownPositioningStyles();
955
- this.dropdownEl.style.transform = "";
956
- this.dropdownEl.style.opacity = "";
949
+ _resetMenuStyles() {
950
+ this.menuEl.style.display = "";
951
+ this._resetMenuPositioningStyles();
952
+ this.menuEl.style.transform = "";
953
+ this.menuEl.style.opacity = "";
957
954
  }
958
- _resetDropdownPositioningStyles() {
959
- this.dropdownEl.style.width = "";
960
- this.dropdownEl.style.height = "";
961
- this.dropdownEl.style.left = "";
962
- this.dropdownEl.style.top = "";
963
- this.dropdownEl.style.transformOrigin = "";
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 = "";
964
961
  }
965
- _moveDropdownToElement(containerEl = null) {
962
+ _moveMenuToElement(containerEl = null) {
966
963
  if (this.options.container) {
967
- this.options.container.append(this.dropdownEl);
964
+ this.options.container.append(this.menuEl);
968
965
  return;
969
966
  }
970
967
  if (containerEl) {
971
- if (!containerEl.contains(this.dropdownEl)) containerEl.append(this.dropdownEl);
968
+ if (!containerEl.contains(this.menuEl)) containerEl.append(this.menuEl);
972
969
  return;
973
970
  }
974
- this.el.after(this.dropdownEl);
971
+ this.el.after(this.menuEl);
975
972
  }
976
- _makeDropdownFocusable() {
977
- if (!this.dropdownEl) return;
978
- this.dropdownEl.popover = "";
979
- this.dropdownEl.tabIndex = 0;
980
- this.dropdownEl.querySelectorAll(":scope li, :scope > hr").forEach((el) => {
981
- 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")) {
982
979
  el.setAttribute("tabindex", "-1");
983
980
  return;
984
981
  }
@@ -986,25 +983,25 @@ var Expressive = (() => {
986
983
  });
987
984
  }
988
985
  _focusFocusedItem() {
989
- if (this.focusedIndex >= 0 && this.focusedIndex < this.dropdownEl.children.length && this.options.autoFocus) {
990
- 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({
991
988
  preventScroll: true
992
989
  });
993
- this.dropdownEl.children[this.focusedIndex].scrollIntoView({
990
+ this.menuEl.children[this.focusedIndex].scrollIntoView({
994
991
  behavior: "smooth",
995
992
  block: "nearest",
996
993
  inline: "nearest"
997
994
  });
998
995
  }
999
996
  }
1000
- _getDropdownPosition(closestOverflowParent) {
997
+ _getMenuPosition(closestOverflowParent) {
1001
998
  const triggerBRect = this.el.getBoundingClientRect();
1002
- const dropdownBRect = this.dropdownEl.getBoundingClientRect();
1003
- let idealHeight = dropdownBRect.height;
1004
- let idealWidth = dropdownBRect.width;
1005
- let idealXPos = triggerBRect.left - dropdownBRect.left;
1006
- let idealYPos = triggerBRect.top - dropdownBRect.top;
1007
- 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 = {
1008
1005
  left: idealXPos,
1009
1006
  top: idealYPos,
1010
1007
  height: idealHeight,
@@ -1013,7 +1010,7 @@ var Expressive = (() => {
1013
1010
  const alignments = Utils.checkPossibleAlignments(
1014
1011
  this.el,
1015
1012
  closestOverflowParent,
1016
- dropdownBounds,
1013
+ menuBounds,
1017
1014
  this.options.coverTrigger ? 0 : triggerBRect.height
1018
1015
  );
1019
1016
  let verticalAlignment = "top";
@@ -1054,10 +1051,10 @@ var Expressive = (() => {
1054
1051
  }
1055
1052
  }
1056
1053
  if (verticalAlignment === "bottom") {
1057
- idealYPos = idealYPos - dropdownBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
1054
+ idealYPos = idealYPos - menuBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
1058
1055
  }
1059
1056
  if (horizontalAlignment === "right") {
1060
- idealXPos = idealXPos - dropdownBRect.width + triggerBRect.width;
1057
+ idealXPos = idealXPos - menuBRect.width + triggerBRect.width;
1061
1058
  }
1062
1059
  return {
1063
1060
  x: idealXPos,
@@ -1070,26 +1067,26 @@ var Expressive = (() => {
1070
1067
  }
1071
1068
  _animateIn() {
1072
1069
  const duration = this.options.inDuration;
1073
- this.dropdownEl.style.transition = "none";
1074
- this.dropdownEl.style.opacity = "0";
1075
- 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)";
1076
1073
  setTimeout(() => {
1077
- this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
1078
- this.dropdownEl.style.opacity = "1";
1079
- 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)";
1080
1077
  }, 1);
1081
1078
  setTimeout(() => {
1082
- if (this.options.autoFocus) this.dropdownEl.focus();
1079
+ if (this.options.autoFocus) this.menuEl.focus();
1083
1080
  if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
1084
1081
  }, duration);
1085
1082
  }
1086
1083
  _animateOut() {
1087
1084
  const duration = this.options.outDuration;
1088
- this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
1089
- this.dropdownEl.style.opacity = "0";
1090
- 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)";
1091
1088
  setTimeout(() => {
1092
- this._resetDropdownStyles();
1089
+ this._resetMenuStyles();
1093
1090
  if (typeof this.options.onCloseEnd === "function")
1094
1091
  this.options.onCloseEnd.call(this, this.el);
1095
1092
  }, duration);
@@ -1104,30 +1101,31 @@ var Expressive = (() => {
1104
1101
  }
1105
1102
  return null;
1106
1103
  }
1107
- _placeDropdown() {
1104
+ _placeMenu() {
1108
1105
  let closestOverflowParent = this._getClosestAncestor(
1109
- this.dropdownEl,
1106
+ this.menuEl,
1110
1107
  (ancestor) => {
1111
1108
  return !["HTML", "BODY"].includes(ancestor.tagName) && getComputedStyle(ancestor).overflow !== "visible";
1112
1109
  }
1113
1110
  );
1114
1111
  if (!closestOverflowParent) {
1115
- closestOverflowParent = !!this.dropdownEl.offsetParent ? this.dropdownEl.offsetParent : this.dropdownEl.parentNode;
1112
+ closestOverflowParent = !!this.menuEl.offsetParent ? this.menuEl.offsetParent : this.menuEl.parentNode;
1116
1113
  }
1117
1114
  if (getComputedStyle(closestOverflowParent).position === "static")
1118
1115
  closestOverflowParent.style.position = "relative";
1119
- const idealWidth = this.options.constrainWidth ? this.el.getBoundingClientRect().width : this.dropdownEl.getBoundingClientRect().width;
1120
- this.dropdownEl.style.width = idealWidth + "px";
1121
- const positionInfo = this._getDropdownPosition(closestOverflowParent);
1122
- this.dropdownEl.style.left = positionInfo.x + "px";
1123
- this.dropdownEl.style.top = positionInfo.y + "px";
1124
- this.dropdownEl.style.height = positionInfo.height + "px";
1125
- this.dropdownEl.style.width = positionInfo.width + "px";
1126
- 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%"}`;
1127
1125
  }
1128
1126
  };
1129
- _Dropdown._dropdowns = [];
1130
- var Dropdown = _Dropdown;
1127
+ _Menu._menus = [];
1128
+ var Menu = _Menu;
1131
1129
 
1132
1130
  // src/ts/components/autocomplete.ts
1133
1131
  var _defaults3 = {
@@ -1135,8 +1133,8 @@ var Expressive = (() => {
1135
1133
  // Autocomplete data set
1136
1134
  onAutocomplete: null,
1137
1135
  // Callback for when autocompleted
1138
- dropdownOptions: {
1139
- // Default dropdown options
1136
+ menuOptions: {
1137
+ // Default menu options
1140
1138
  autoFocus: false,
1141
1139
  closeOnClick: false,
1142
1140
  coverTrigger: false
@@ -1152,7 +1150,7 @@ var Expressive = (() => {
1152
1150
  )
1153
1151
  );
1154
1152
  },
1155
- maxDropDownHeight: "300px",
1153
+ maxMenuHeight: "300px",
1156
1154
  allowUnsafeHTML: false,
1157
1155
  selected: []
1158
1156
  };
@@ -1237,19 +1235,19 @@ var Expressive = (() => {
1237
1235
  this._resetAutocomplete();
1238
1236
  if (inputText.length >= this.options.minLength) {
1239
1237
  this.isOpen = true;
1240
- this._renderDropdown();
1238
+ this._renderMenu();
1241
1239
  }
1242
- if (!this.dropdown.isOpen) {
1240
+ if (!this.menu.isOpen) {
1243
1241
  setTimeout(() => {
1244
- this.dropdown.open();
1242
+ this.menu.open();
1245
1243
  }, 0);
1246
- } else this.dropdown.recalculateDimensions();
1244
+ } else this.menu.recalculateDimensions();
1247
1245
  };
1248
1246
  /**
1249
1247
  * Hide autocomplete.
1250
1248
  */
1251
1249
  this.close = () => {
1252
- this.dropdown.close();
1250
+ this.menu.close();
1253
1251
  };
1254
1252
  this.el["Expressive_Autocomplete"] = this;
1255
1253
  this.options = {
@@ -1264,7 +1262,7 @@ var Expressive = (() => {
1264
1262
  this.menuItems = this.options.data || [];
1265
1263
  this.$active = null;
1266
1264
  this._mousedown = false;
1267
- this._setupDropdown();
1265
+ this._setupMenu();
1268
1266
  this._setupEventHandlers();
1269
1267
  }
1270
1268
  static get defaults() {
@@ -1295,7 +1293,7 @@ var Expressive = (() => {
1295
1293
  }
1296
1294
  destroy() {
1297
1295
  this._removeEventHandlers();
1298
- this._removeDropdown();
1296
+ this._removeMenu();
1299
1297
  this.el["Expressive_Autocomplete"] = void 0;
1300
1298
  }
1301
1299
  _setupEventHandlers() {
@@ -1324,34 +1322,33 @@ var Expressive = (() => {
1324
1322
  this.container.removeEventListener("touchend", this._handleContainerMouseupAndTouchend);
1325
1323
  }
1326
1324
  }
1327
- _setupDropdown() {
1325
+ _setupMenu() {
1328
1326
  this.container = document.createElement("menu");
1329
- this.container.style.maxHeight = this.options.maxDropDownHeight;
1327
+ this.container.style.maxHeight = this.options.maxMenuHeight;
1330
1328
  this.container.id = `autocomplete-options-${Utils.guid()}`;
1331
1329
  this.container.classList.add("autocomplete-content");
1332
1330
  this.container.ariaExpanded = "true";
1333
1331
  this.el.setAttribute("data-target", this.container.id);
1334
1332
  this.menuItems.forEach((menuItem) => {
1335
- const itemElement = this._createDropdownItem(menuItem);
1333
+ const itemElement = this._createMenuItem(menuItem);
1336
1334
  this.container.append(itemElement);
1337
1335
  });
1338
1336
  this.el.parentElement.appendChild(this.container);
1339
- const dropdownOptions = {
1340
- ..._Autocomplete.defaults.dropdownOptions,
1341
- ...this.options.dropdownOptions
1337
+ const menuOptions = {
1338
+ ..._Autocomplete.defaults.menuOptions,
1339
+ ...this.options.menuOptions
1342
1340
  };
1343
- const userOnItemClick = dropdownOptions.onItemClick;
1344
- dropdownOptions.onItemClick = (li) => {
1341
+ const userOnItemClick = menuOptions.onItemClick;
1342
+ menuOptions.onItemClick = (li) => {
1345
1343
  if (!li) return;
1346
1344
  const entryID = li.getAttribute("data-id");
1347
1345
  this.selectOption(entryID);
1348
- if (userOnItemClick && typeof userOnItemClick === "function")
1349
- userOnItemClick.call(this.dropdown, this.el);
1346
+ if (typeof userOnItemClick === "function") userOnItemClick.call(this.menu, li);
1350
1347
  };
1351
- this.dropdown = Dropdown.init(this.el, dropdownOptions);
1348
+ this.menu = Menu.init(this.el, menuOptions);
1352
1349
  const label = this.el.parentElement.querySelector("label");
1353
1350
  if (label) this.el.after(label);
1354
- this.el.removeEventListener("click", this.dropdown._handleClick);
1351
+ this.el.removeEventListener("click", this.menu._handleClick);
1355
1352
  if (!this.options.isMultiSelect && !(this.options.selected.length === 0)) {
1356
1353
  const selectedValue = this.menuItems.filter((value) => value.id === this.selectedValues[0].id);
1357
1354
  this.el.value = selectedValue[0].text;
@@ -1363,7 +1360,7 @@ var Expressive = (() => {
1363
1360
  this.el.parentElement.appendChild(div);
1364
1361
  this._updateSelectedInfo();
1365
1362
  }
1366
- _removeDropdown() {
1363
+ _removeMenu() {
1367
1364
  this.container.ariaExpanded = "false";
1368
1365
  this.container.parentNode.removeChild(this.container);
1369
1366
  }
@@ -1386,7 +1383,7 @@ var Expressive = (() => {
1386
1383
  }
1387
1384
  return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
1388
1385
  }
1389
- _createDropdownItem(entry) {
1386
+ _createMenuItem(entry) {
1390
1387
  const item = document.createElement("li");
1391
1388
  item.setAttribute("data-id", entry.id);
1392
1389
  item.setAttribute(
@@ -1453,13 +1450,13 @@ var Expressive = (() => {
1453
1450
  item.style.gridTemplateColumns = getGridConfig();
1454
1451
  return item;
1455
1452
  }
1456
- _renderDropdown() {
1453
+ _renderMenu() {
1457
1454
  this._resetAutocomplete();
1458
1455
  if (this.menuItems.length === 0) {
1459
1456
  this.menuItems = this.selectedValues;
1460
1457
  }
1461
1458
  for (let i = 0; i < this.menuItems.length; i++) {
1462
- const item = this._createDropdownItem(this.menuItems[i]);
1459
+ const item = this._createMenuItem(this.menuItems[i]);
1463
1460
  this.container.append(item);
1464
1461
  }
1465
1462
  }
@@ -1490,7 +1487,7 @@ var Expressive = (() => {
1490
1487
  * Updates the visible or selectable items shown in the menu.
1491
1488
  * @param menuItems Items to be available.
1492
1489
  * @param selected Selected item ids
1493
- * @param open Option to conditionally open dropdown
1490
+ * @param open Option to conditionally open menu
1494
1491
  */
1495
1492
  setMenuItems(menuItems, selected = null, open = true) {
1496
1493
  this.menuItems = menuItems;
@@ -1501,7 +1498,7 @@ var Expressive = (() => {
1501
1498
  );
1502
1499
  }
1503
1500
  if (this.options.isMultiSelect) {
1504
- this._renderDropdown();
1501
+ this._renderMenu();
1505
1502
  } else {
1506
1503
  this._refreshInputText();
1507
1504
  }
@@ -1523,7 +1520,7 @@ var Expressive = (() => {
1523
1520
  else this.selectedValues = this.selectedValues.filter(
1524
1521
  (selectedEntry) => selectedEntry.id !== entry.id
1525
1522
  );
1526
- this._renderDropdown();
1523
+ this._renderMenu();
1527
1524
  this.el.focus();
1528
1525
  } else {
1529
1526
  this.selectedValues = [entry];
@@ -1841,12 +1838,14 @@ var Expressive = (() => {
1841
1838
  constructor(el, options) {
1842
1839
  super(el, options, _Range);
1843
1840
  this._handleRangeChange = () => {
1841
+ this._clampDual();
1844
1842
  this._sync();
1845
1843
  this.thumb.classList.add("active");
1846
1844
  };
1847
1845
  this._handleRangeMousedownTouchstart = (e) => {
1848
1846
  this._mousedown = true;
1849
1847
  this.el.classList.add("active");
1848
+ this._clampDual();
1850
1849
  this._sync();
1851
1850
  if (e.type !== "input") {
1852
1851
  this.thumb.classList.add("active");
@@ -1854,6 +1853,7 @@ var Expressive = (() => {
1854
1853
  };
1855
1854
  this._handleRangeInputMousemoveTouchmove = () => {
1856
1855
  if (this._mousedown) {
1856
+ this._clampDual();
1857
1857
  this._sync();
1858
1858
  this.thumb.classList.add("active");
1859
1859
  }
@@ -1938,16 +1938,48 @@ var Expressive = (() => {
1938
1938
  _isVertical() {
1939
1939
  return !!this.el.closest(".vertical");
1940
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
+ }
1941
1959
  _sync() {
1942
- const max = parseFloat(this.el.getAttribute("max")) || 100;
1943
- const min = parseFloat(this.el.getAttribute("min")) || 0;
1944
- const val = parseFloat(this.el.value) || 0;
1945
- const percent = max === min ? 0 : (val - min) / (max - min);
1960
+ const percent = this._fraction(this.el);
1961
+ const fraction = `${percent * 100}%`;
1946
1962
  const left = this.el.offsetLeft;
1947
1963
  const top = this.el.offsetTop;
1948
1964
  const width = this.el.offsetWidth;
1949
1965
  const height = this.el.offsetHeight;
1950
- 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
+ }
1951
1983
  this.value.textContent = this.el.value;
1952
1984
  if (this._isVertical()) {
1953
1985
  this.thumb.style.left = `${left + width / 2}px`;
@@ -2035,6 +2067,170 @@ var Expressive = (() => {
2035
2067
  _Dialogs._down = null;
2036
2068
  var Dialogs = _Dialogs;
2037
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
+
2038
2234
  // src/ts/behaviors/forms.ts
2039
2235
  var Forms = class _Forms {
2040
2236
  /**
@@ -2938,178 +3134,10 @@ var Expressive = (() => {
2938
3134
  }
2939
3135
  };
2940
3136
 
2941
- // src/ts/components/collapsible.ts
2942
- var _defaults9 = {
2943
- accordion: true,
2944
- onOpenStart: null,
2945
- onOpenEnd: null,
2946
- onCloseStart: null,
2947
- onCloseEnd: null
2948
- };
2949
- var Collapsible = class _Collapsible extends Component {
2950
- constructor(el, options) {
2951
- super(el, options, _Collapsible);
2952
- this._items = [];
2953
- this._endTimers = [];
2954
- this._wrappedBodies = [];
2955
- /**
2956
- * Open collapsible section.
2957
- * @param index 0-based index of the section to open.
2958
- */
2959
- this.open = (index) => {
2960
- const item = this._items[index];
2961
- if (!item || this._isOpen(item)) return;
2962
- if (this.options.accordion) {
2963
- this._items.forEach((other, i) => {
2964
- if (i !== index && this._isOpen(other)) this.close(i);
2965
- });
2966
- }
2967
- this._setOpen(item, true);
2968
- };
2969
- /**
2970
- * Close collapsible section.
2971
- * @param index 0-based index of the section to close.
2972
- */
2973
- this.close = (index) => {
2974
- const item = this._items[index];
2975
- if (!item || !this._isOpen(item)) return;
2976
- this._setOpen(item, false);
2977
- };
2978
- this._handleToggle = (e) => {
2979
- const item = e.target;
2980
- if (!(item instanceof HTMLDetailsElement)) return;
2981
- if (!this._items.includes(item)) return;
2982
- this._notify(item, item.open);
2983
- };
2984
- this.el["Expressive_Collapsible"] = this;
2985
- const accordion = options.accordion !== void 0 ? options.accordion : !el.classList.contains("expandable");
2986
- this.options = {
2987
- ..._Collapsible.defaults,
2988
- ...options,
2989
- accordion
2990
- };
2991
- this._groupName = el.id ? `collapsible-${el.id}` : `collapsible-${Utils.guid()}`;
2992
- this._items = this._collectItems();
2993
- this._wrapDetailsBodies();
2994
- this._setupItems();
2995
- this._setupEventHandlers();
2996
- }
2997
- static get defaults() {
2998
- return _defaults9;
2999
- }
3000
- /**
3001
- * Initializes instances of Collapsible.
3002
- * @param els HTML elements.
3003
- * @param options Component options.
3004
- */
3005
- static init(els, options = {}) {
3006
- return super.init(els, options, _Collapsible);
3007
- }
3008
- static getInstance(el) {
3009
- return el["Expressive_Collapsible"];
3010
- }
3011
- destroy() {
3012
- this._removeEventHandlers();
3013
- this._endTimers.forEach((id) => clearTimeout(id));
3014
- this._endTimers = [];
3015
- this._unwrapDetailsBodies();
3016
- this.el["Expressive_Collapsible"] = void 0;
3017
- }
3018
- _collectItems() {
3019
- return Array.from(this.el.querySelectorAll(":scope > details"));
3020
- }
3021
- _setupItems() {
3022
- if (this.options.accordion) {
3023
- this._items.forEach((item) => {
3024
- if (item instanceof HTMLDetailsElement && !item.getAttribute("name")) {
3025
- item.setAttribute("name", this._groupName);
3026
- }
3027
- });
3028
- }
3029
- const opened = this._items.filter((item) => this._isOpen(item));
3030
- if (this.options.accordion && opened.length > 1) {
3031
- opened.slice(1).forEach((item) => {
3032
- if (item instanceof HTMLDetailsElement) item.open = false;
3033
- });
3034
- }
3035
- }
3036
- _isOpen(item) {
3037
- return item instanceof HTMLDetailsElement && item.open;
3038
- }
3039
- _setOpen(item, open) {
3040
- if (item instanceof HTMLDetailsElement) item.open = open;
3041
- }
3042
- _wrapDetailsBodies() {
3043
- this._items.forEach((item) => {
3044
- if (!(item instanceof HTMLDetailsElement)) return;
3045
- if (item.querySelector(":scope > :not(summary)")) {
3046
- const already = Array.from(item.children).filter((c) => c.tagName !== "SUMMARY");
3047
- if (already.length === 1 && already[0].tagName === "DIV") {
3048
- this._wrappedBodies.push(already[0]);
3049
- return;
3050
- }
3051
- }
3052
- const body = document.createElement("div");
3053
- Array.from(item.childNodes).forEach((node) => {
3054
- if (node instanceof HTMLElement && node.tagName === "SUMMARY") return;
3055
- body.appendChild(node);
3056
- });
3057
- item.appendChild(body);
3058
- this._wrappedBodies.push(body);
3059
- });
3060
- }
3061
- _unwrapDetailsBodies() {
3062
- this._wrappedBodies.forEach((body) => {
3063
- const parent = body.parentNode;
3064
- if (!parent) return;
3065
- while (body.firstChild) parent.insertBefore(body.firstChild, body);
3066
- body.remove();
3067
- });
3068
- this._wrappedBodies = [];
3069
- }
3070
- _bodyOf(item) {
3071
- return item.querySelector(":scope > :not(summary)");
3072
- }
3073
- _setupEventHandlers() {
3074
- this.el.addEventListener("toggle", this._handleToggle, true);
3075
- }
3076
- _removeEventHandlers() {
3077
- this.el.removeEventListener("toggle", this._handleToggle, true);
3078
- }
3079
- _notify(item, opening) {
3080
- const start = opening ? this.options.onOpenStart : this.options.onCloseStart;
3081
- if (typeof start === "function") start.call(this, item);
3082
- const end = opening ? this.options.onOpenEnd : this.options.onCloseEnd;
3083
- if (typeof end !== "function") return;
3084
- const target = this._bodyOf(item) ?? item;
3085
- let done = false;
3086
- const finish = () => {
3087
- if (done) return;
3088
- done = true;
3089
- target.removeEventListener("transitionend", onEnd);
3090
- end.call(this, item);
3091
- };
3092
- const onEnd = (ev) => {
3093
- if (ev.target !== target) return;
3094
- finish();
3095
- };
3096
- target.addEventListener("transitionend", onEnd);
3097
- this._endTimers.push(window.setTimeout(finish, this._durationMs() + 50));
3098
- }
3099
- _durationMs() {
3100
- const raw = getComputedStyle(this.el).getPropertyValue("--md-comp-collapsible-duration").trim();
3101
- if (!raw) return 500;
3102
- if (raw.endsWith("ms")) return parseFloat(raw);
3103
- if (raw.endsWith("s")) return parseFloat(raw) * 1e3;
3104
- const n = parseFloat(raw);
3105
- return Number.isFinite(n) ? n : 500;
3106
- }
3107
- };
3108
-
3109
3137
  // src/ts/components/select.ts
3110
- var _defaults10 = {
3138
+ var _defaults9 = {
3111
3139
  classes: "",
3112
- dropdownOptions: {}
3140
+ menuOptions: {}
3113
3141
  };
3114
3142
  var FormSelect = class _FormSelect extends Component {
3115
3143
  constructor(el, options) {
@@ -3135,7 +3163,7 @@ var Expressive = (() => {
3135
3163
  if (li?.id) this.input.setAttribute("aria-activedescendant", li.id);
3136
3164
  };
3137
3165
  this._handleInputClick = () => {
3138
- if (this.dropdown && this.dropdown.isOpen) {
3166
+ if (this.menu && this.menu.isOpen) {
3139
3167
  this._setValueToInput();
3140
3168
  this._setSelectedStates();
3141
3169
  }
@@ -3152,11 +3180,11 @@ var Expressive = (() => {
3152
3180
  this._values = [];
3153
3181
  this._createdWrapper = false;
3154
3182
  this._originalLabelFor = null;
3155
- this._setupDropdown();
3183
+ this._setupMenu();
3156
3184
  this._setupEventHandlers();
3157
3185
  }
3158
3186
  static get defaults() {
3159
- return _defaults10;
3187
+ return _defaults9;
3160
3188
  }
3161
3189
  /**
3162
3190
  * Initializes instances of FormSelect.
@@ -3171,21 +3199,21 @@ var Expressive = (() => {
3171
3199
  }
3172
3200
  destroy() {
3173
3201
  this._removeEventHandlers();
3174
- this.dropdown?.destroy();
3175
- this._removeDropdown();
3202
+ this.menu?.destroy();
3203
+ this._removeMenu();
3176
3204
  this.el.tabIndex = this.nativeTabIndex;
3177
3205
  this.el["Expressive_FormSelect"] = void 0;
3178
3206
  }
3179
3207
  /**
3180
- * 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.
3181
3209
  *
3182
3210
  * Assigning `select.value` from script fires no `change` event, so nothing
3183
3211
  * else syncs the visible input text or the `.selected` state on the virtual
3184
3212
  * options. Adding or removing `<option>`s also requires this — the menu is
3185
- * rebuilt from the native list, the field and Dropdown instance stay put.
3213
+ * rebuilt from the native list, the field and Menu instance stay put.
3186
3214
  */
3187
3215
  refresh() {
3188
- if (!this.dropdownOptions) return;
3216
+ if (!this.menuEl) return;
3189
3217
  this._rebuildOptions();
3190
3218
  this._setValueToInput();
3191
3219
  this._setSelectedStates();
@@ -3194,22 +3222,22 @@ var Expressive = (() => {
3194
3222
  this._setupOptionHandlers();
3195
3223
  this.el.addEventListener("change", this._handleSelectChange);
3196
3224
  this.input.addEventListener("click", this._handleInputClick);
3197
- this.dropdownOptions.addEventListener("focusin", this._handleOptionFocus);
3225
+ this.menuEl.addEventListener("focusin", this._handleOptionFocus);
3198
3226
  }
3199
3227
  _removeEventHandlers() {
3200
3228
  this._removeOptionHandlers();
3201
3229
  this.el.removeEventListener("change", this._handleSelectChange);
3202
3230
  this.input?.removeEventListener("click", this._handleInputClick);
3203
- this.dropdownOptions?.removeEventListener("focusin", this._handleOptionFocus);
3231
+ this.menuEl?.removeEventListener("focusin", this._handleOptionFocus);
3204
3232
  }
3205
3233
  _setupOptionHandlers() {
3206
- this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3234
+ this.menuEl.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3207
3235
  el.addEventListener("click", this._handleOptionClick);
3208
3236
  el.addEventListener("keydown", this._handleOptionKeydown);
3209
3237
  });
3210
3238
  }
3211
3239
  _removeOptionHandlers() {
3212
- this.dropdownOptions?.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3240
+ this.menuEl?.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3213
3241
  el.removeEventListener("click", this._handleOptionClick);
3214
3242
  el.removeEventListener("keydown", this._handleOptionKeydown);
3215
3243
  });
@@ -3240,24 +3268,24 @@ var Expressive = (() => {
3240
3268
  new Event("change", { bubbles: true, cancelable: true, composed: true })
3241
3269
  );
3242
3270
  }
3243
- if (!this.isMultiple) this.dropdown?.close();
3271
+ if (!this.isMultiple) this.menu?.close();
3244
3272
  }
3245
- _setupDropdown() {
3273
+ _setupMenu() {
3246
3274
  this.labelEl = this.el.labels?.[0] ?? null;
3247
3275
  this._setupWrapper();
3248
3276
  this._hideNativeSelect();
3249
3277
  if (this.el.disabled) this.wrapper.classList.add("disabled");
3250
- this.dropdownOptions = document.createElement("menu");
3251
- this.dropdownOptions.id = `select-options-${Utils.guid()}`;
3252
- this.dropdownOptions.setAttribute("popover", "auto");
3253
- this.dropdownOptions.setAttribute("role", "listbox");
3254
- this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
3255
- if (this.isMultiple) this.dropdownOptions.classList.add("multiple-select-dropdown");
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");
3256
3284
  this._buildOptions();
3257
- this.wrapper.append(this.dropdownOptions);
3285
+ this.wrapper.append(this.menuEl);
3258
3286
  this._buildInput();
3259
3287
  this._buildCaret();
3260
- this._initDropdown();
3288
+ this._initMenu();
3261
3289
  this._setSelectedStates();
3262
3290
  if (this.labelEl) this.input.after(this.labelEl);
3263
3291
  }
@@ -3287,10 +3315,10 @@ var Expressive = (() => {
3287
3315
  _buildInput() {
3288
3316
  this.input = document.createElement("input");
3289
3317
  this.input.id = "select-input-" + Utils.guid();
3290
- this.input.classList.add("dropdown-trigger");
3318
+ this.input.classList.add("menu-trigger");
3291
3319
  this.input.type = "text";
3292
3320
  this.input.readOnly = true;
3293
- this.input.setAttribute("data-target", this.dropdownOptions.id);
3321
+ this.input.setAttribute("data-target", this.menuEl.id);
3294
3322
  this.input.ariaReadOnly = "true";
3295
3323
  this.input.ariaRequired = this.el.hasAttribute("required").toString();
3296
3324
  if (this.el.disabled) this.input.disabled = true;
@@ -3303,7 +3331,7 @@ var Expressive = (() => {
3303
3331
  this.input.setAttribute("role", "combobox");
3304
3332
  this.input.setAttribute("aria-haspopup", "listbox");
3305
3333
  this.input.ariaExpanded = "false";
3306
- this.input.setAttribute("aria-controls", this.dropdownOptions.id);
3334
+ this.input.setAttribute("aria-controls", this.menuEl.id);
3307
3335
  this.input.placeholder = " ";
3308
3336
  if (this.labelEl) {
3309
3337
  this._originalLabelFor = this.labelEl.htmlFor;
@@ -3318,38 +3346,38 @@ var Expressive = (() => {
3318
3346
  caret.setAttribute("aria-hidden", "true");
3319
3347
  this.wrapper.prepend(caret);
3320
3348
  }
3321
- _initDropdown() {
3349
+ _initMenu() {
3322
3350
  if (this.el.disabled) return;
3323
- const dropdownOptions = { ...this.options.dropdownOptions };
3324
- dropdownOptions.coverTrigger = false;
3325
- const userOnOpenEnd = dropdownOptions.onOpenEnd;
3326
- const userOnCloseEnd = dropdownOptions.onCloseEnd;
3327
- dropdownOptions.onOpenEnd = () => {
3328
- const selectedOption = this.dropdownOptions.querySelector(".selected");
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");
3329
3357
  if (selectedOption) {
3330
3358
  Utils.keyDown = true;
3331
- this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
3332
- this.dropdown._focusFocusedItem();
3359
+ this.menu.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
3360
+ this.menu._focusFocusedItem();
3333
3361
  Utils.keyDown = false;
3334
- if (this.dropdown.isScrollable) {
3335
- let scrollOffset = selectedOption.getBoundingClientRect().top - this.dropdownOptions.getBoundingClientRect().top;
3336
- scrollOffset -= this.dropdownOptions.clientHeight / 2;
3337
- this.dropdownOptions.scrollTop = scrollOffset;
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;
3338
3366
  }
3339
3367
  if (selectedOption.id) this.input.setAttribute("aria-activedescendant", selectedOption.id);
3340
3368
  }
3341
3369
  this.input.ariaExpanded = "true";
3342
3370
  if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3343
- userOnOpenEnd.call(this.dropdown, this.el);
3371
+ userOnOpenEnd.call(this.menu, this.el);
3344
3372
  };
3345
- dropdownOptions.onCloseEnd = () => {
3373
+ menuOptions.onCloseEnd = () => {
3346
3374
  this.input.ariaExpanded = "false";
3347
3375
  this.input.removeAttribute("aria-activedescendant");
3348
3376
  if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3349
- userOnCloseEnd.call(this.dropdown, this.el);
3377
+ userOnCloseEnd.call(this.menu, this.el);
3350
3378
  };
3351
- dropdownOptions.closeOnClick = false;
3352
- this.dropdown = Dropdown.init(this.input, dropdownOptions);
3379
+ menuOptions.closeOnClick = false;
3380
+ this.menu = Menu.init(this.input, menuOptions);
3353
3381
  }
3354
3382
  _nativeOptions() {
3355
3383
  return Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
@@ -3376,7 +3404,7 @@ var Expressive = (() => {
3376
3404
  groupLabel.setAttribute("role", "presentation");
3377
3405
  groupLabel.textContent = realOption.getAttribute("label") ?? "";
3378
3406
  groupParent.replaceChildren(groupLabel);
3379
- this.dropdownOptions.append(groupParent);
3407
+ this.menuEl.append(groupParent);
3380
3408
  const groupChildren = [];
3381
3409
  const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3382
3410
  selectOptions.forEach((child) => {
@@ -3390,18 +3418,18 @@ var Expressive = (() => {
3390
3418
  }
3391
3419
  _rebuildOptions() {
3392
3420
  this._removeOptionHandlers();
3393
- this.dropdownOptions.replaceChildren();
3421
+ this.menuEl.replaceChildren();
3394
3422
  this._buildOptions();
3395
3423
  this._setupOptionHandlers();
3396
- this.dropdown?._makeDropdownFocusable();
3424
+ this.menu?._makeMenuFocusable();
3397
3425
  }
3398
3426
  _addOptionToValues(realOption, virtualOption) {
3399
3427
  this._values.push({ el: realOption, optionEl: virtualOption });
3400
3428
  }
3401
- _removeDropdown() {
3429
+ _removeMenu() {
3402
3430
  this.wrapper?.querySelector(":scope > .caret")?.remove();
3403
3431
  this.input?.remove();
3404
- this.dropdownOptions?.remove();
3432
+ this.menuEl?.remove();
3405
3433
  const hide = this.el.parentElement;
3406
3434
  if (hide?.classList.contains("hide-select")) hide.replaceWith(this.el);
3407
3435
  if (this.labelEl && this._originalLabelFor !== null) {
@@ -3452,7 +3480,7 @@ var Expressive = (() => {
3452
3480
  img.ariaHidden = "true";
3453
3481
  li.prepend(img);
3454
3482
  }
3455
- this.dropdownOptions.append(li);
3483
+ this.menuEl.append(li);
3456
3484
  return li;
3457
3485
  }
3458
3486
  _selectValue(value) {
@@ -3510,7 +3538,7 @@ var Expressive = (() => {
3510
3538
  const cb = value.optionEl.querySelector('input[type="checkbox"]');
3511
3539
  if (cb) cb.checked = optionIsSelected;
3512
3540
  if (optionIsSelected) {
3513
- this._activateOption(this.dropdownOptions, value.optionEl);
3541
+ this._activateOption(this.menuEl, value.optionEl);
3514
3542
  } else {
3515
3543
  value.optionEl.classList.remove("selected");
3516
3544
  value.optionEl.ariaSelected = "false";
@@ -3530,7 +3558,7 @@ var Expressive = (() => {
3530
3558
  };
3531
3559
 
3532
3560
  // src/ts/plugins/dockedDisplayPlugin.ts
3533
- var _defaults11 = {
3561
+ var _defaults10 = {
3534
3562
  margin: 5,
3535
3563
  transition: 10,
3536
3564
  duration: 250,
@@ -3579,7 +3607,7 @@ var Expressive = (() => {
3579
3607
  };
3580
3608
  this.el = el;
3581
3609
  this.options = {
3582
- ..._defaults11,
3610
+ ..._defaults10,
3583
3611
  ...options
3584
3612
  };
3585
3613
  this.container = document.createElement("div");
@@ -3600,7 +3628,7 @@ var Expressive = (() => {
3600
3628
  };
3601
3629
 
3602
3630
  // src/ts/components/datepicker.ts
3603
- var _defaults12 = {
3631
+ var _defaults11 = {
3604
3632
  // the default output format for the input field value
3605
3633
  format: "mmm dd, yyyy",
3606
3634
  // Used to create date object from current input string
@@ -3865,7 +3893,7 @@ var Expressive = (() => {
3865
3893
  }
3866
3894
  }
3867
3895
  static get defaults() {
3868
- return _defaults12;
3896
+ return _defaults11;
3869
3897
  }
3870
3898
  /**
3871
3899
  * Initializes instances of Datepicker.
@@ -4448,11 +4476,11 @@ var Expressive = (() => {
4448
4476
  const monthSelect = this.calendarEl.querySelector(".orig-select-month");
4449
4477
  FormSelect.init(yearSelect, {
4450
4478
  classes: "select-year",
4451
- dropdownOptions: { container: document.body, constrainWidth: false }
4479
+ menuOptions: { container: document.body, constrainWidth: false }
4452
4480
  });
4453
4481
  FormSelect.init(monthSelect, {
4454
4482
  classes: "select-month",
4455
- dropdownOptions: { container: document.body, constrainWidth: false }
4483
+ menuOptions: { container: document.body, constrainWidth: false }
4456
4484
  });
4457
4485
  yearSelect.addEventListener("change", this._handleYearChange);
4458
4486
  monthSelect.addEventListener("change", this._handleMonthChange);
@@ -4583,7 +4611,7 @@ var Expressive = (() => {
4583
4611
  var Datepicker = _Datepicker;
4584
4612
 
4585
4613
  // src/ts/components/lightbox.ts
4586
- var _defaults13 = {
4614
+ var _defaults12 = {
4587
4615
  inDuration: 275,
4588
4616
  outDuration: 200,
4589
4617
  onOpenStart: null,
@@ -4702,7 +4730,7 @@ var Expressive = (() => {
4702
4730
  this._setupEventHandlers();
4703
4731
  }
4704
4732
  static get defaults() {
4705
- return _defaults13;
4733
+ return _defaults12;
4706
4734
  }
4707
4735
  /**
4708
4736
  * Initializes instances of Lightbox.
@@ -4867,7 +4895,7 @@ var Expressive = (() => {
4867
4895
  };
4868
4896
 
4869
4897
  // src/ts/components/parallax.ts
4870
- var _defaults14 = {};
4898
+ var _defaults13 = {};
4871
4899
  var Parallax = class _Parallax extends Component {
4872
4900
  constructor(el, options) {
4873
4901
  super(el, options, _Parallax);
@@ -4881,7 +4909,7 @@ var Expressive = (() => {
4881
4909
  }
4882
4910
  }
4883
4911
  static get defaults() {
4884
- return _defaults14;
4912
+ return _defaults13;
4885
4913
  }
4886
4914
  static init(els, options = {}) {
4887
4915
  return super.init(els, options, _Parallax);
@@ -4894,98 +4922,9 @@ var Expressive = (() => {
4894
4922
  }
4895
4923
  };
4896
4924
 
4897
- // src/ts/components/pushpin.ts
4898
- var _defaults15 = {
4899
- top: 0,
4900
- bottom: Infinity,
4901
- offset: 0,
4902
- onPositionChange: null
4903
- };
4904
- var _Pushpin = class _Pushpin extends Component {
4905
- constructor(el, options) {
4906
- super(el, options, _Pushpin);
4907
- this.el["Expressive_Pushpin"] = this;
4908
- this.options = {
4909
- ..._Pushpin.defaults,
4910
- ...options
4911
- };
4912
- this.originalOffset = this.el.offsetTop;
4913
- _Pushpin._pushpins.push(this);
4914
- this._setupEventHandlers();
4915
- this._updatePosition();
4916
- }
4917
- static get defaults() {
4918
- return _defaults15;
4919
- }
4920
- /**
4921
- * Initializes instances of Pushpin.
4922
- * @param els HTML elements.
4923
- * @param options Component options.
4924
- */
4925
- static init(els, options = {}) {
4926
- return super.init(els, options, _Pushpin);
4927
- }
4928
- static getInstance(el) {
4929
- return el["Expressive_Pushpin"];
4930
- }
4931
- destroy() {
4932
- this.el.style.top = null;
4933
- this._removePinClasses();
4934
- const index = _Pushpin._pushpins.indexOf(this);
4935
- _Pushpin._pushpins.splice(index, 1);
4936
- if (_Pushpin._pushpins.length === 0) {
4937
- this._removeEventHandlers();
4938
- }
4939
- this.el["Expressive_Pushpin"] = void 0;
4940
- }
4941
- static _updateElements() {
4942
- for (let i = 0; i < _Pushpin._pushpins.length; i++) {
4943
- _Pushpin._pushpins[i]._updatePosition();
4944
- }
4945
- }
4946
- _setupEventHandlers() {
4947
- document.addEventListener("scroll", _Pushpin._updateElements, { passive: true });
4948
- }
4949
- _removeEventHandlers() {
4950
- document.removeEventListener("scroll", _Pushpin._updateElements);
4951
- }
4952
- _updatePosition() {
4953
- const scrolled = Utils.getDocumentScrollTop() + this.options.offset;
4954
- if (this.options.top <= scrolled && this.options.bottom >= scrolled && !this.el.classList.contains("pinned")) {
4955
- this._removePinClasses();
4956
- this.el.style.top = `${this.options.offset}px`;
4957
- this.el.classList.add("pinned");
4958
- if (typeof this.options.onPositionChange === "function") {
4959
- this.options.onPositionChange.call(this, "pinned");
4960
- }
4961
- }
4962
- if (scrolled < this.options.top && !this.el.classList.contains("pin-top")) {
4963
- this._removePinClasses();
4964
- this.el.style.top = "0";
4965
- this.el.classList.add("pin-top");
4966
- if (typeof this.options.onPositionChange === "function") {
4967
- this.options.onPositionChange.call(this, "pin-top");
4968
- }
4969
- }
4970
- if (scrolled > this.options.bottom && !this.el.classList.contains("pin-bottom")) {
4971
- this._removePinClasses();
4972
- this.el.classList.add("pin-bottom");
4973
- this.el.style.top = `${this.options.bottom - this.originalOffset}px`;
4974
- if (typeof this.options.onPositionChange === "function") {
4975
- this.options.onPositionChange.call(this, "pin-bottom");
4976
- }
4977
- }
4978
- }
4979
- _removePinClasses() {
4980
- this.el.classList.remove("pin-top", "pinned", "pin-bottom");
4981
- }
4982
- };
4983
- _Pushpin._pushpins = [];
4984
- var Pushpin = _Pushpin;
4985
-
4986
4925
  // src/ts/components/scrollspy.ts
4987
4926
  var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
4988
- var _defaults16 = {
4927
+ var _defaults14 = {
4989
4928
  scrollOffset: 200,
4990
4929
  activeClass: "active",
4991
4930
  getActiveElement: _defaultGetActiveElement,
@@ -5008,7 +4947,7 @@ var Expressive = (() => {
5008
4947
  _ScrollSpy._observer?.observe(this.el);
5009
4948
  }
5010
4949
  static get defaults() {
5011
- return _defaults16;
4950
+ return _defaults14;
5012
4951
  }
5013
4952
  static init(els, options = {}) {
5014
4953
  return super.init(els, options, _ScrollSpy);
@@ -5130,7 +5069,7 @@ var Expressive = (() => {
5130
5069
  var ScrollSpy = _ScrollSpy;
5131
5070
 
5132
5071
  // src/ts/components/sidenav.ts
5133
- var _defaults17 = {
5072
+ var _defaults15 = {
5134
5073
  edge: "left",
5135
5074
  draggable: true,
5136
5075
  dragTargetWidth: "10px",
@@ -5273,7 +5212,7 @@ var Expressive = (() => {
5273
5212
  _Sidenav._sidenavs.push(this);
5274
5213
  }
5275
5214
  static get defaults() {
5276
- return _defaults17;
5215
+ return _defaults15;
5277
5216
  }
5278
5217
  /**
5279
5218
  * Initializes instances of Sidenav.
@@ -5458,8 +5397,114 @@ var Expressive = (() => {
5458
5397
  _Sidenav._sidenavs = [];
5459
5398
  var Sidenav = _Sidenav;
5460
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);
5475
+ }
5476
+ static get defaults() {
5477
+ return _defaults16;
5478
+ }
5479
+ static init(els, options = {}) {
5480
+ return super.init(els, options, _NavigationRail);
5481
+ }
5482
+ static getInstance(el) {
5483
+ return el["Expressive_NavigationRail"];
5484
+ }
5485
+ destroy() {
5486
+ this.el.removeEventListener("click", this._onClick);
5487
+ document.removeEventListener("keydown", this._onKeyDown);
5488
+ this.el["Expressive_NavigationRail"] = void 0;
5489
+ }
5490
+ _findToggle() {
5491
+ const first = this.el.querySelector(":scope > button:not(.button)");
5492
+ return first instanceof HTMLButtonElement ? first : null;
5493
+ }
5494
+ _isCompact() {
5495
+ return this._mql.matches;
5496
+ }
5497
+ _isModal() {
5498
+ return this.el.classList.contains("modal") || this._isCompact();
5499
+ }
5500
+ _sync() {
5501
+ this.el.setAttribute("aria-expanded", this.isExpanded ? "true" : "false");
5502
+ this._toggle?.setAttribute("aria-expanded", this.isExpanded ? "true" : "false");
5503
+ }
5504
+ };
5505
+
5461
5506
  // src/ts/components/slider.ts
5462
- var _defaults18 = {
5507
+ var _defaults17 = {
5463
5508
  indicators: true,
5464
5509
  height: 400,
5465
5510
  duration: 500,
@@ -5607,7 +5652,7 @@ var Expressive = (() => {
5607
5652
  this.start();
5608
5653
  }
5609
5654
  static get defaults() {
5610
- return _defaults18;
5655
+ return _defaults17;
5611
5656
  }
5612
5657
  /**
5613
5658
  * Initializes instances of Slider.
@@ -5760,7 +5805,7 @@ var Expressive = (() => {
5760
5805
  };
5761
5806
 
5762
5807
  // src/ts/components/tabs.ts
5763
- var _defaults19 = {
5808
+ var _defaults18 = {
5764
5809
  duration: 300,
5765
5810
  onShow: null,
5766
5811
  swipeable: false,
@@ -5838,7 +5883,7 @@ var Expressive = (() => {
5838
5883
  this._setupEventHandlers();
5839
5884
  }
5840
5885
  static get defaults() {
5841
- return _defaults19;
5886
+ return _defaults18;
5842
5887
  }
5843
5888
  /**
5844
5889
  * Initializes instances of Tabs.
@@ -6005,229 +6050,8 @@ var Expressive = (() => {
6005
6050
  }
6006
6051
  };
6007
6052
 
6008
- // src/ts/components/tapTarget.ts
6009
- var _defaults20 = {
6010
- onOpen: null,
6011
- onClose: null
6012
- };
6013
- var _TapTarget = class _TapTarget extends Component {
6014
- constructor(el, options) {
6015
- super(el, options, _TapTarget);
6016
- this.wrapper = null;
6017
- this.waveEl = null;
6018
- this.contentEl = null;
6019
- this._createdWrapper = false;
6020
- this._createdWave = false;
6021
- this._usePopover = false;
6022
- this._liftedStatic = false;
6023
- this._opening = false;
6024
- /**
6025
- * Open Tap Target.
6026
- */
6027
- this.open = () => {
6028
- if (this.isOpen || !this.originEl || !this.wrapper) return;
6029
- _TapTarget._taptargets.forEach((other) => {
6030
- if (other !== this) other.close();
6031
- });
6032
- this._calculatePositioning();
6033
- if (typeof this.options.onOpen === "function") {
6034
- this.options.onOpen.call(this, this.originEl);
6035
- }
6036
- this.isOpen = true;
6037
- this.wrapper.classList.add("open");
6038
- this.originEl.setAttribute("aria-expanded", "true");
6039
- if (!this._usePopover) {
6040
- this.originEl.classList.add("tap-target-origin");
6041
- if (getComputedStyle(this.originEl).position === "static") {
6042
- this.originEl.style.position = "relative";
6043
- this._liftedStatic = true;
6044
- }
6045
- }
6046
- if (this._usePopover) {
6047
- this._opening = true;
6048
- try {
6049
- this.wrapper.showPopover();
6050
- } catch {
6051
- }
6052
- requestAnimationFrame(() => {
6053
- this._opening = false;
6054
- });
6055
- }
6056
- };
6057
- /**
6058
- * Close Tap Target.
6059
- */
6060
- this.close = () => {
6061
- if (!this.isOpen) return;
6062
- if (typeof this.options.onClose === "function" && this.originEl) {
6063
- this.options.onClose.call(this, this.originEl);
6064
- }
6065
- this.isOpen = false;
6066
- this.wrapper?.classList.remove("open");
6067
- this.originEl?.setAttribute("aria-expanded", "false");
6068
- this.originEl?.classList.remove("tap-target-origin");
6069
- if (this._liftedStatic && this.originEl) {
6070
- this.originEl.style.position = "";
6071
- this._liftedStatic = false;
6072
- }
6073
- if (this._usePopover && this.wrapper) {
6074
- try {
6075
- this.wrapper.hidePopover();
6076
- } catch {
6077
- }
6078
- }
6079
- };
6080
- // Built once per instance; a fresh throttle per event never fires.
6081
- this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
6082
- this._handleOriginKeydown = (e) => {
6083
- if (Utils.keys.ENTER.includes(e.key) || e.key === " ") {
6084
- e.preventDefault();
6085
- this._handleTargetToggle();
6086
- }
6087
- };
6088
- this._handleTargetToggle = () => {
6089
- if (!this.isOpen) this.open();
6090
- else this.close();
6091
- };
6092
- this._handleResize = () => {
6093
- if (this.isOpen) this._calculatePositioning();
6094
- };
6095
- this._handlePopoverToggle = (e) => {
6096
- const state = "newState" in e ? String(e.newState) : "";
6097
- if (state === "open") return;
6098
- if (this._opening) {
6099
- try {
6100
- this.wrapper?.showPopover();
6101
- } catch {
6102
- }
6103
- return;
6104
- }
6105
- if (this.isOpen) this.close();
6106
- };
6107
- this.el["Expressive_TapTarget"] = this;
6108
- this.options = {
6109
- ..._TapTarget.defaults,
6110
- ...options
6111
- };
6112
- this.isOpen = false;
6113
- this.originEl = el.dataset.target ? document.getElementById(el.dataset.target) : null;
6114
- if (!this.originEl) {
6115
- console.error(`TapTarget: no element with id "${el.dataset.target ?? ""}" to attach to`);
6116
- return;
6117
- }
6118
- this._setup();
6119
- this._calculatePositioning();
6120
- this._setupEventHandlers();
6121
- _TapTarget._taptargets.push(this);
6122
- }
6123
- static get defaults() {
6124
- return _defaults20;
6125
- }
6126
- static init(els, options = {}) {
6127
- return super.init(els, options, _TapTarget);
6128
- }
6129
- static getInstance(el) {
6130
- return el["Expressive_TapTarget"];
6131
- }
6132
- destroy() {
6133
- this.close();
6134
- this._removeEventHandlers();
6135
- this._teardownDom();
6136
- this.el["Expressive_TapTarget"] = void 0;
6137
- const index = _TapTarget._taptargets.indexOf(this);
6138
- if (index >= 0) _TapTarget._taptargets.splice(index, 1);
6139
- }
6140
- _setup() {
6141
- const parent = this.el.parentElement;
6142
- if (parent?.classList.contains("tap-target-wrapper")) {
6143
- this.wrapper = parent;
6144
- } else {
6145
- this.wrapper = document.createElement("div");
6146
- this.wrapper.classList.add("tap-target-wrapper");
6147
- this.el.before(this.wrapper);
6148
- this.wrapper.append(this.el);
6149
- this._createdWrapper = true;
6150
- }
6151
- this.contentEl = this.el.querySelector(".tap-target-content");
6152
- if (!this.contentEl) {
6153
- this.contentEl = document.createElement("div");
6154
- this.contentEl.className = "tap-target-content";
6155
- while (this.el.firstChild) this.contentEl.append(this.el.firstChild);
6156
- this.el.append(this.contentEl);
6157
- }
6158
- this.waveEl = this.el.querySelector(".tap-target-wave") ?? this.wrapper.querySelector(".tap-target-wave");
6159
- if (!this.waveEl) {
6160
- this.waveEl = document.createElement("div");
6161
- this.waveEl.className = "tap-target-wave";
6162
- this._createdWave = true;
6163
- }
6164
- this.el.prepend(this.waveEl);
6165
- this.el.setAttribute("role", "dialog");
6166
- this._labelFromHeading();
6167
- const origin = this.originEl;
6168
- origin.setAttribute("aria-expanded", "false");
6169
- origin.setAttribute("aria-controls", this.el.id || this._ensureId());
6170
- this._usePopover = typeof this.wrapper.showPopover === "function";
6171
- if (this._usePopover) {
6172
- this.wrapper.setAttribute("popover", "auto");
6173
- }
6174
- }
6175
- _ensureId() {
6176
- if (!this.el.id) this.el.id = `tap-target-${Utils.guid()}`;
6177
- return this.el.id;
6178
- }
6179
- _labelFromHeading() {
6180
- const heading = this.contentEl?.querySelector("h1, h2, h3, h4, h5, h6");
6181
- if (!heading) return;
6182
- if (!heading.id) heading.id = `tap-target-title-${Utils.guid()}`;
6183
- this.el.setAttribute("aria-labelledby", heading.id);
6184
- }
6185
- _teardownDom() {
6186
- if (this._createdWave) this.waveEl?.remove();
6187
- if (this._createdWrapper && this.wrapper) {
6188
- this.wrapper.before(this.el);
6189
- this.wrapper.remove();
6190
- }
6191
- this.wrapper = null;
6192
- this.waveEl = null;
6193
- }
6194
- _setupEventHandlers() {
6195
- if (!this.originEl) return;
6196
- this.originEl.addEventListener("click", this._handleTargetToggle);
6197
- if (!this.originEl.matches('button, a, [tabindex], [role="button"]')) {
6198
- this.originEl.tabIndex = 0;
6199
- this.originEl.addEventListener("keydown", this._handleOriginKeydown);
6200
- }
6201
- this.wrapper?.addEventListener("toggle", this._handlePopoverToggle);
6202
- window.addEventListener("resize", this._handleThrottledResize, { passive: true });
6203
- }
6204
- _removeEventHandlers() {
6205
- if (!this.originEl) return;
6206
- this.originEl.removeEventListener("click", this._handleTargetToggle);
6207
- this.originEl.removeEventListener("keydown", this._handleOriginKeydown);
6208
- this.wrapper?.removeEventListener("toggle", this._handlePopoverToggle);
6209
- window.removeEventListener("resize", this._handleThrottledResize);
6210
- }
6211
- _calculatePositioning() {
6212
- if (!this.originEl || !this.wrapper) return;
6213
- const rect = this.originEl.getBoundingClientRect();
6214
- const x = rect.left + rect.width / 2;
6215
- const y = rect.top + rect.height / 2;
6216
- const size = Math.max(rect.width, rect.height, 1);
6217
- this.wrapper.style.setProperty("--md-comp-tap-target-x", `${x}px`);
6218
- this.wrapper.style.setProperty("--md-comp-tap-target-y", `${y}px`);
6219
- this.wrapper.style.setProperty("--md-comp-tap-target-origin-size", `${size}px`);
6220
- const vertical = y <= window.innerHeight / 2 ? "top" : "bottom";
6221
- const onCenter = x >= window.innerWidth * 0.25 && x <= window.innerWidth * 0.75;
6222
- const horizontal = onCenter ? "center" : x <= window.innerWidth / 2 ? "left" : "right";
6223
- this.wrapper.dataset.edge = `${vertical}-${horizontal}`;
6224
- }
6225
- };
6226
- _TapTarget._taptargets = [];
6227
- var TapTarget = _TapTarget;
6228
-
6229
6053
  // src/ts/components/timepicker.ts
6230
- var _defaults21 = {
6054
+ var _defaults19 = {
6231
6055
  dialRadius: 135,
6232
6056
  outerRadius: 105,
6233
6057
  innerRadius: 70,
@@ -6425,7 +6249,7 @@ var Expressive = (() => {
6425
6249
  }
6426
6250
  }
6427
6251
  static get defaults() {
6428
- return _defaults21;
6252
+ return _defaults19;
6429
6253
  }
6430
6254
  /**
6431
6255
  * Initializes instances of Timepicker.
@@ -6794,8 +6618,8 @@ var Expressive = (() => {
6794
6618
  </div>`;
6795
6619
  var Timepicker = _Timepicker;
6796
6620
 
6797
- // src/ts/components/toasts.ts
6798
- var _defaults22 = {
6621
+ // src/ts/components/snackbar.ts
6622
+ var _defaults20 = {
6799
6623
  text: "",
6800
6624
  action: "",
6801
6625
  onAction: null,
@@ -6807,97 +6631,109 @@ var Expressive = (() => {
6807
6631
  completeCallback: null,
6808
6632
  activationPercent: 0.8
6809
6633
  };
6810
- var _Toast = class _Toast {
6811
- constructor(options) {
6634
+ var _Snackbar = class _Snackbar {
6635
+ constructor(options = {}) {
6636
+ this._dismissed = false;
6812
6637
  this.options = {
6813
- ..._Toast.defaults,
6638
+ ..._Snackbar.defaults,
6814
6639
  ...options
6815
6640
  };
6641
+ if (options.displayLength === void 0 && this.options.action) {
6642
+ this.options.displayLength = 1e4;
6643
+ }
6816
6644
  this.message = this.options.text;
6817
6645
  this.panning = false;
6818
6646
  this.timeRemaining = this.options.displayLength;
6819
- if (_Toast._toasts.length === 0) {
6820
- _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;
6821
6654
  }
6822
- _Toast._toasts.push(this);
6823
- const toastElement = this._createToast();
6824
- toastElement["Expressive_Toast"] = this;
6825
- this.el = toastElement;
6655
+ if (!_Snackbar._container || !_Snackbar._container.isConnected) {
6656
+ _Snackbar._createContainer();
6657
+ }
6658
+ _Snackbar._snackbars.push(this);
6659
+ const snackbarElement = this._createSnackbar();
6660
+ snackbarElement["Expressive_Snackbar"] = this;
6661
+ this.el = snackbarElement;
6826
6662
  this._animateIn();
6827
6663
  this._setTimer();
6828
6664
  }
6829
6665
  static get defaults() {
6830
- return _defaults22;
6666
+ return _defaults20;
6831
6667
  }
6832
6668
  static getInstance(el) {
6833
- return el["Expressive_Toast"];
6669
+ return el["Expressive_Snackbar"];
6834
6670
  }
6835
6671
  static _createContainer() {
6836
6672
  const container = document.createElement("div");
6837
- container.setAttribute("id", "toast-container");
6838
- container.addEventListener("touchstart", _Toast._onDragStart);
6839
- container.addEventListener("touchmove", _Toast._onDragMove);
6840
- container.addEventListener("touchend", _Toast._onDragEnd);
6841
- container.addEventListener("mousedown", _Toast._onDragStart);
6842
- document.addEventListener("mousemove", _Toast._onDragMove);
6843
- 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);
6844
6680
  document.body.appendChild(container);
6845
- _Toast._container = container;
6681
+ _Snackbar._container = container;
6846
6682
  }
6847
6683
  static _removeContainer() {
6848
- document.removeEventListener("mousemove", _Toast._onDragMove);
6849
- document.removeEventListener("mouseup", _Toast._onDragEnd);
6850
- _Toast._container.remove();
6851
- _Toast._container = null;
6684
+ document.removeEventListener("mousemove", _Snackbar._onDragMove);
6685
+ document.removeEventListener("mouseup", _Snackbar._onDragEnd);
6686
+ _Snackbar._container.remove();
6687
+ _Snackbar._container = null;
6852
6688
  }
6853
6689
  static _onDragStart(e) {
6854
6690
  const target = e.target;
6855
6691
  if (target && !target.closest("button, a") && target.closest(".snackbar")) {
6856
- const toastElem = target.closest(".snackbar");
6857
- const toast = toastElem["Expressive_Toast"];
6858
- if (!toast) return;
6859
- toast.panning = true;
6860
- toast._pauseTimer();
6861
- _Toast._draggedToast = toast;
6862
- toast.el.classList.add("panning");
6863
- toast.el.style.transition = "";
6864
- toast.startingXPos = _Toast._xPos(e);
6865
- toast.time = Date.now();
6866
- toast.xPos = _Toast._xPos(e);
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);
6867
6703
  }
6868
6704
  }
6869
6705
  static _onDragMove(e) {
6870
- if (!!_Toast._draggedToast) {
6706
+ if (!!_Snackbar._draggedSnackbar) {
6871
6707
  e.preventDefault();
6872
- const toast = _Toast._draggedToast;
6873
- toast.deltaX = Math.abs(toast.xPos - _Toast._xPos(e));
6874
- toast.xPos = _Toast._xPos(e);
6875
- toast.velocityX = toast.deltaX / (Date.now() - toast.time);
6876
- toast.time = Date.now();
6877
- const totalDeltaX = toast.xPos - toast.startingXPos;
6878
- const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
6879
- toast.el.style.transform = `translateX(${totalDeltaX}px)`;
6880
- 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();
6881
6717
  }
6882
6718
  }
6883
6719
  static _onDragEnd() {
6884
- if (!!_Toast._draggedToast) {
6885
- const toast = _Toast._draggedToast;
6886
- toast.panning = false;
6887
- toast.el.classList.remove("panning");
6888
- const totalDeltaX = toast.xPos - toast.startingXPos;
6889
- const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
6890
- 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;
6891
6727
  if (shouldBeDismissed) {
6892
- toast.wasSwiped = true;
6893
- toast.dismiss();
6728
+ snackbar.wasSwiped = true;
6729
+ snackbar.dismiss();
6894
6730
  } else {
6895
- toast.el.style.transition = "transform .2s, opacity .2s";
6896
- toast.el.style.transform = "";
6897
- toast.el.style.opacity = "";
6898
- toast._resumeTimer();
6731
+ snackbar.el.style.transition = "transform .2s, opacity .2s";
6732
+ snackbar.el.style.transform = "";
6733
+ snackbar.el.style.opacity = "";
6734
+ snackbar._resumeTimer();
6899
6735
  }
6900
- _Toast._draggedToast = null;
6736
+ _Snackbar._draggedSnackbar = null;
6901
6737
  }
6902
6738
  }
6903
6739
  static _xPos(e) {
@@ -6907,30 +6743,30 @@ var Expressive = (() => {
6907
6743
  return e.clientX;
6908
6744
  }
6909
6745
  /**
6910
- * dismiss all toasts.
6746
+ * dismiss all snackbars.
6911
6747
  */
6912
6748
  static dismissAll() {
6913
- for (const toast of [..._Toast._toasts]) {
6914
- toast.dismiss();
6749
+ for (const snackbar of [..._Snackbar._snackbars]) {
6750
+ snackbar.dismiss();
6915
6751
  }
6916
6752
  }
6917
- _createToast() {
6918
- let toast = this.options.toastId ? document.getElementById(this.options.toastId) : document.createElement("div");
6919
- if (toast instanceof HTMLTemplateElement) {
6920
- const node = toast.content.cloneNode(true);
6921
- 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;
6922
6758
  }
6923
- toast.classList.add("snackbar");
6924
- toast.setAttribute("role", "status");
6925
- toast.setAttribute("aria-live", "polite");
6926
- 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");
6927
6763
  if (this.options.classes.length > 0) {
6928
- toast.classList.add(...this.options.classes.split(" ").filter(Boolean));
6764
+ snackbar.classList.add(...this.options.classes.split(" ").filter(Boolean));
6929
6765
  }
6930
6766
  if (this.message) {
6931
6767
  const text = document.createElement("p");
6932
6768
  text.textContent = this.message;
6933
- toast.replaceChildren(text);
6769
+ snackbar.replaceChildren(text);
6934
6770
  }
6935
6771
  if (this.options.action) {
6936
6772
  const action = document.createElement("button");
@@ -6943,7 +6779,7 @@ var Expressive = (() => {
6943
6779
  }
6944
6780
  this.dismiss();
6945
6781
  });
6946
- toast.appendChild(action);
6782
+ snackbar.appendChild(action);
6947
6783
  }
6948
6784
  if (this.options.dismissible) {
6949
6785
  const close = document.createElement("button");
@@ -6959,20 +6795,21 @@ var Expressive = (() => {
6959
6795
  e.stopPropagation();
6960
6796
  this.dismiss();
6961
6797
  });
6962
- toast.appendChild(close);
6798
+ snackbar.appendChild(close);
6963
6799
  }
6964
- _Toast._container.appendChild(toast);
6965
- return toast;
6800
+ _Snackbar._container.appendChild(snackbar);
6801
+ return snackbar;
6966
6802
  }
6967
6803
  _animateIn() {
6968
6804
  this.el.style.display = "";
6969
6805
  this.el.style.opacity = "0";
6806
+ this.el.style.transform = "translateY(24px)";
6970
6807
  this.el.style.transition = `
6971
- top ${this.options.inDuration}ms ease,
6808
+ transform ${this.options.inDuration}ms ease,
6972
6809
  opacity ${this.options.inDuration}ms ease
6973
6810
  `;
6974
6811
  setTimeout(() => {
6975
- this.el.style.top = "0";
6812
+ this.el.style.transform = "";
6976
6813
  this.el.style.opacity = "1";
6977
6814
  }, 1);
6978
6815
  }
@@ -6980,7 +6817,7 @@ var Expressive = (() => {
6980
6817
  * Arm the dismissal timer.
6981
6818
  *
6982
6819
  * One timeout, not a 20ms interval ticking a counter down: the old form woke
6983
- * 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
6984
6821
  * number. Dragging pauses the countdown via _pauseTimer/_resumeTimer instead.
6985
6822
  */
6986
6823
  _setTimer() {
@@ -7001,9 +6838,11 @@ var Expressive = (() => {
7001
6838
  this._setTimer();
7002
6839
  }
7003
6840
  /**
7004
- * Dismiss toast with animation.
6841
+ * Dismiss snackbar with animation.
7005
6842
  */
7006
6843
  dismiss() {
6844
+ if (this._dismissed) return;
6845
+ this._dismissed = true;
7007
6846
  clearTimeout(this.counterTimeout);
7008
6847
  this.counterTimeout = null;
7009
6848
  const activationDistance = this.el.offsetWidth * this.options.activationPercent;
@@ -7023,24 +6862,24 @@ var Expressive = (() => {
7023
6862
  if (typeof this.options.completeCallback === "function") {
7024
6863
  this.options.completeCallback();
7025
6864
  }
7026
- if (this.el.id != this.options.toastId) {
6865
+ if (this.el.id != this.options.snackbarId) {
7027
6866
  this.el.remove();
7028
- const index = _Toast._toasts.indexOf(this);
7029
- if (index >= 0) _Toast._toasts.splice(index, 1);
7030
- if (_Toast._toasts.length === 0 && _Toast._container) {
7031
- _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();
7032
6871
  }
7033
6872
  }
7034
6873
  }, this.options.outDuration);
7035
6874
  }
7036
6875
  };
7037
- _Toast._toasts = [];
7038
- _Toast._container = null;
7039
- _Toast._draggedToast = null;
7040
- var Toast = _Toast;
6876
+ _Snackbar._snackbars = [];
6877
+ _Snackbar._container = null;
6878
+ _Snackbar._draggedSnackbar = null;
6879
+ var Snackbar = _Snackbar;
7041
6880
 
7042
6881
  // src/ts/components/tooltip.ts
7043
- var _defaults23 = {
6882
+ var _defaults21 = {
7044
6883
  exitDelay: 200,
7045
6884
  enterDelay: 0,
7046
6885
  text: "",
@@ -7108,7 +6947,7 @@ var Expressive = (() => {
7108
6947
  this._setupEventHandlers();
7109
6948
  }
7110
6949
  static get defaults() {
7111
- return _defaults23;
6950
+ return _defaults21;
7112
6951
  }
7113
6952
  /**
7114
6953
  * Initializes instances of Tooltip.
@@ -7288,17 +7127,15 @@ var Expressive = (() => {
7288
7127
  Cards: { component: Cards, selector: CARDS_SELECTOR },
7289
7128
  Carousel: { component: Carousel, selector: ".carousel" },
7290
7129
  Chips: { component: Chips, selector: ".chips" },
7291
- Collapsible: { component: Collapsible, selector: ".collapsible" },
7292
7130
  Datepicker: { component: Datepicker, selector: ".datepicker" },
7293
- Dropdown: { component: Dropdown, selector: ".dropdown-trigger" },
7131
+ Menu: { component: Menu, selector: ".menu-trigger" },
7294
7132
  Lightbox: { component: Lightbox, selector: ".lightboxed" },
7295
7133
  Parallax: { component: Parallax, selector: ".parallax" },
7296
- Pushpin: { component: Pushpin, selector: ".pushpin" },
7297
7134
  ScrollSpy: { component: ScrollSpy, selector: ".scrollspy" },
7298
7135
  FormSelect: { component: FormSelect, selector: "select" },
7299
7136
  Sidenav: { component: Sidenav, selector: ".sidenav" },
7137
+ NavigationRail: { component: NavigationRail, selector: ".navigation-rail" },
7300
7138
  Tabs: { component: Tabs, selector: ".tabs" },
7301
- TapTarget: { component: TapTarget, selector: ".tap-target" },
7302
7139
  Timepicker: { component: Timepicker, selector: ".timepicker" },
7303
7140
  Tooltip: { component: Tooltip, selector: ".tooltipped" },
7304
7141
  FloatingActionButton: {
@@ -7315,7 +7152,7 @@ var Expressive = (() => {
7315
7152
  }
7316
7153
 
7317
7154
  // src/ts/index.ts
7318
- var version = "0.4.0";
7155
+ var version = "0.5.0";
7319
7156
  if (typeof document !== "undefined") {
7320
7157
  document.addEventListener("keydown", Utils.docHandleKeydown, true);
7321
7158
  document.addEventListener("keyup", Utils.docHandleKeyup, true);
@@ -7328,6 +7165,8 @@ var Expressive = (() => {
7328
7165
  Range.Init();
7329
7166
  Cards.Init();
7330
7167
  Dialogs.Init();
7168
+ BottomSheets.Init();
7169
+ SideSheets.Init();
7331
7170
  return __toCommonJS(index_exports);
7332
7171
  })();
7333
7172
  //# sourceMappingURL=expressive.js.map