@expressivecss/expressive 0.3.0 → 0.4.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 (74) hide show
  1. package/README.md +1 -1
  2. package/dist/css/expressive.css +1011 -1339
  3. package/dist/css/expressive.css.map +1 -1
  4. package/dist/css/expressive.min.css +1 -1
  5. package/dist/css/expressive.min.css.map +1 -1
  6. package/dist/js/expressive.cjs +701 -853
  7. package/dist/js/expressive.cjs.map +4 -4
  8. package/dist/js/expressive.js +701 -853
  9. package/dist/js/expressive.js.map +4 -4
  10. package/dist/js/expressive.min.js +10 -20
  11. package/dist/js/expressive.min.js.map +4 -4
  12. package/dist/js/expressive.mjs +701 -854
  13. package/dist/js/expressive.mjs.map +4 -4
  14. package/dist/types/components/autocomplete.d.ts +2 -9
  15. package/dist/types/components/buttons.d.ts +2 -2
  16. package/dist/types/components/cards.d.ts +3 -6
  17. package/dist/types/components/carousel.d.ts +3 -3
  18. package/dist/types/components/characterCounter.d.ts +3 -5
  19. package/dist/types/components/chips.d.ts +2 -2
  20. package/dist/types/components/collapsible.d.ts +6 -23
  21. package/dist/types/components/datepicker.d.ts +2 -8
  22. package/dist/types/components/dropdown.d.ts +11 -2
  23. package/dist/types/components/index.d.ts +0 -1
  24. package/dist/types/components/lightbox.d.ts +2 -2
  25. package/dist/types/components/parallax.d.ts +2 -8
  26. package/dist/types/components/pushpin.d.ts +2 -2
  27. package/dist/types/components/range.d.ts +2 -2
  28. package/dist/types/components/registry.d.ts +0 -4
  29. package/dist/types/components/scrollspy.d.ts +26 -50
  30. package/dist/types/components/select.d.ts +20 -6
  31. package/dist/types/components/sidenav.d.ts +40 -55
  32. package/dist/types/components/slider.d.ts +2 -2
  33. package/dist/types/components/tabs.d.ts +2 -2
  34. package/dist/types/components/tapTarget.d.ts +2 -2
  35. package/dist/types/components/timepicker.d.ts +2 -4
  36. package/dist/types/components/tooltip.d.ts +2 -2
  37. package/dist/types/core/component.d.ts +4 -4
  38. package/dist/types/index.d.ts +1 -1
  39. package/package.json +2 -2
  40. package/src/sass/README.md +2 -6
  41. package/src/sass/abstracts/_breakpoints.scss +0 -16
  42. package/src/sass/abstracts/_variables.scss +0 -21
  43. package/src/sass/base/_grid.scss +0 -19
  44. package/src/sass/components/_badges.scss +1 -1
  45. package/src/sass/components/_buttons.scss +22 -54
  46. package/src/sass/components/_cards.scss +50 -123
  47. package/src/sass/components/_carousel.scss +4 -6
  48. package/src/sass/components/_collapsible.scss +13 -15
  49. package/src/sass/components/_collection.scss +9 -27
  50. package/src/sass/components/_datepicker.scss +1 -15
  51. package/src/sass/components/_dropdown.scss +110 -14
  52. package/src/sass/components/_index.scss +1 -0
  53. package/src/sass/components/_modal.scss +13 -31
  54. package/src/sass/components/_navbar.scss +9 -6
  55. package/src/sass/components/_page-footer.scss +134 -15
  56. package/src/sass/components/_parallax.scss +7 -28
  57. package/src/sass/components/_preloader.scss +145 -300
  58. package/src/sass/components/_scrollspy.scss +18 -0
  59. package/src/sass/components/_sidenav.scss +226 -120
  60. package/src/sass/components/_table_of_contents.scss +30 -14
  61. package/src/sass/components/_tabs.scss +54 -35
  62. package/src/sass/components/_tapTarget.scss +2 -6
  63. package/src/sass/components/_toast.scss +10 -11
  64. package/src/sass/components/_toolbar.scss +2 -2
  65. package/src/sass/components/_tooltip.scss +4 -9
  66. package/src/sass/components/_transitions.scss +0 -5
  67. package/src/sass/components/forms/_index.scss +0 -5
  68. package/src/sass/components/forms/_input-fields.scss +49 -52
  69. package/src/sass/components/forms/_select.scss +175 -60
  70. package/src/sass/components/forms/_switches.scss +21 -8
  71. package/src/sass/utilities/_helpers.scss +1 -3
  72. package/src/sass/utilities/_typescale.scss +0 -5
  73. package/src/sass/utilities/_visibility.scss +2 -2
  74. package/dist/types/components/modal.d.ts +0 -45
@@ -2,9 +2,6 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __typeError = (msg) => {
6
- throw TypeError(msg);
7
- };
8
5
  var __export = (target, all) => {
9
6
  for (var name in all)
10
7
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -18,9 +15,6 @@ var __copyProps = (to, from, except, desc) => {
18
15
  return to;
19
16
  };
20
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
22
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
23
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
24
18
 
25
19
  // src/ts/index.ts
26
20
  var index_exports = {};
@@ -39,7 +33,6 @@ __export(index_exports, {
39
33
  FormSelect: () => FormSelect,
40
34
  Forms: () => Forms,
41
35
  Lightbox: () => Lightbox,
42
- Modal: () => Modal,
43
36
  Parallax: () => Parallax,
44
37
  Pushpin: () => Pushpin,
45
38
  Range: () => Range,
@@ -271,7 +264,7 @@ var _Utils = class _Utils {
271
264
  * Renders a button with optional callback function
272
265
  */
273
266
  static createButton(container, text, className = [], visibility = true, callback = null) {
274
- className = className.concat(["btn", "waves-effect", "text"]);
267
+ className = className.concat(["waves-effect", "text"]);
275
268
  const button = document.createElement("button");
276
269
  button.className = className.join(" ");
277
270
  button.style.visibility = visibility ? "visible" : "hidden";
@@ -450,11 +443,9 @@ var Component = class {
450
443
  // src/ts/components/cards.ts
451
444
  var _defaults = {
452
445
  onOpen: null,
453
- onClose: null,
454
- inDuration: 225,
455
- outDuration: 300
446
+ onClose: null
456
447
  };
457
- var CARDS_SELECTOR = ".card, article:has(> aside), article:has(.card-reveal)";
448
+ var CARDS_SELECTOR = "article:has(> aside)";
458
449
  var Cards = class _Cards extends Component {
459
450
  constructor(el, options) {
460
451
  super(el, options, _Cards);
@@ -500,16 +491,10 @@ var Cards = class _Cards extends Component {
500
491
  * Show card reveal.
501
492
  */
502
493
  this.open = () => {
503
- if (this.isOpen) return;
494
+ if (this.isOpen || !this.cardReveal) return;
504
495
  this.isOpen = true;
505
- this.el.style.overflow = "hidden";
506
- this.cardReveal.style.display = "block";
507
496
  this.cardReveal.ariaExpanded = "true";
508
497
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = 0;
509
- setTimeout(() => {
510
- this.cardReveal.style.transition = `transform ${this.options.outDuration}ms ease`;
511
- this.cardReveal.style.transform = "translateY(-100%)";
512
- }, 1);
513
498
  if (typeof this.options.onOpen === "function") {
514
499
  this.options.onOpen.call(this);
515
500
  }
@@ -519,17 +504,11 @@ var Cards = class _Cards extends Component {
519
504
  * Hide card reveal.
520
505
  */
521
506
  this.close = () => {
522
- if (!this.isOpen) return;
507
+ if (!this.isOpen || !this.cardReveal) return;
523
508
  this.isOpen = false;
524
- this.cardReveal.style.transition = `transform ${this.options.inDuration}ms ease`;
525
- this.cardReveal.style.transform = "translateY(0)";
526
- setTimeout(() => {
527
- this.cardReveal.style.display = "none";
528
- this.cardReveal.ariaExpanded = "false";
529
- this._activators.forEach((el) => el.tabIndex = 0);
530
- if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
531
- this.el.style.overflow = this.initialOverflow;
532
- }, this.options.inDuration);
509
+ this.cardReveal.ariaExpanded = "false";
510
+ this._activators.forEach((el) => el.tabIndex = 0);
511
+ if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
533
512
  if (typeof this.options.onClose === "function") {
534
513
  this.options.onClose.call(this);
535
514
  }
@@ -541,15 +520,14 @@ var Cards = class _Cards extends Component {
541
520
  ...options
542
521
  };
543
522
  this._activators = [];
544
- this.cardReveal = this.el.querySelector(":scope > aside, .card-reveal");
523
+ this.cardReveal = this.el.querySelector(":scope > aside");
545
524
  if (this.cardReveal) {
546
- this.initialOverflow = getComputedStyle(this.el).overflow;
547
525
  this._activators = Array.from(this.el.querySelectorAll(".activator"));
548
526
  this._activators.forEach((el2) => {
549
527
  if (el2) el2.tabIndex = 0;
550
528
  });
551
529
  this.cardRevealClose = this.cardReveal.querySelector(
552
- ".card-title, :scope > :is(h1, h2, h3, h4, h5, h6)"
530
+ ":scope > :is(h1, h2, h3, h4, h5, h6)"
553
531
  );
554
532
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
555
533
  this.cardReveal.ariaExpanded = "false";
@@ -626,7 +604,7 @@ var _Dropdown = class _Dropdown extends Component {
626
604
  this.close();
627
605
  return;
628
606
  }
629
- const leaveToDropdownContent = !!toEl.closest(".dropdown-content, menu");
607
+ const leaveToDropdownContent = !!(this.dropdownEl && toEl && this.dropdownEl.contains(toEl));
630
608
  let leaveToActiveDropdownTrigger = false;
631
609
  const closestTrigger = toEl.closest(".dropdown-trigger");
632
610
  if (closestTrigger && !!closestTrigger["Expressive_Dropdown"] && closestTrigger["Expressive_Dropdown"].isOpen) {
@@ -638,9 +616,10 @@ var _Dropdown = class _Dropdown extends Component {
638
616
  };
639
617
  this._handleDocumentClick = (e) => {
640
618
  const target = e.target;
641
- if (this.options.closeOnClick && target.closest(".dropdown-content, menu") && !this.isTouchMoving) {
619
+ if (this._isSubmenuTriggerClick(target)) return;
620
+ if (this.options.closeOnClick && this.dropdownEl?.contains(target) && !this.isTouchMoving) {
642
621
  this.close();
643
- } else if (!target.closest(".dropdown-content, menu")) {
622
+ } else if (!this.dropdownEl?.contains(target)) {
644
623
  setTimeout(() => {
645
624
  if (this.isOpen) {
646
625
  this.close();
@@ -658,14 +637,29 @@ var _Dropdown = class _Dropdown extends Component {
658
637
  };
659
638
  this._handleDocumentTouchmove = (e) => {
660
639
  const target = e.target;
661
- if (target.closest(".dropdown-content, menu")) {
640
+ if (this.dropdownEl?.contains(target)) {
662
641
  this.isTouchMoving = true;
663
642
  }
664
643
  };
665
644
  this._handleDropdownClick = (e) => {
645
+ const target = e.target;
646
+ const li = target.closest("li");
647
+ if (li && this._isSubmenuTriggerClick(target)) {
648
+ e.preventDefault();
649
+ e.stopPropagation();
650
+ this._toggleSubmenu(li);
651
+ return;
652
+ }
666
653
  if (typeof this.options.onItemClick === "function") {
667
- const itemEl = e.target.closest("li");
668
- this.options.onItemClick.call(this, itemEl);
654
+ this.options.onItemClick.call(this, li);
655
+ }
656
+ };
657
+ this._handleSubmenuAlign = (e) => {
658
+ const target = e.target;
659
+ if (!(target instanceof Element)) return;
660
+ const li = target.closest("li");
661
+ if (li?.querySelector(":scope > menu") && this.dropdownEl?.contains(li)) {
662
+ this._alignSubmenu(li);
669
663
  }
670
664
  };
671
665
  this._handleDropdownKeydown = (e) => {
@@ -673,37 +667,70 @@ var _Dropdown = class _Dropdown extends Component {
673
667
  if (Utils.keys.TAB.includes(e.key)) {
674
668
  e.preventDefault();
675
669
  this.close();
670
+ } else if (Utils.keys.ARROW_RIGHT.includes(e.key) && this.isOpen) {
671
+ const li = this._focusedRow(e);
672
+ if (li?.querySelector(":scope > menu")) {
673
+ e.preventDefault();
674
+ li.classList.add("open");
675
+ this._alignSubmenu(li);
676
+ this._syncSubmenuAria(li, true);
677
+ const first = li.querySelector(":scope > menu > li");
678
+ first?.focus();
679
+ }
680
+ } else if (Utils.keys.ARROW_LEFT.includes(e.key) && this.isOpen) {
681
+ const submenu = this._containingSubmenu(e);
682
+ if (submenu) {
683
+ e.preventDefault();
684
+ const parentLi = submenu.parentElement;
685
+ parentLi.classList.remove("open", "submenu-start");
686
+ this._syncSubmenuAria(parentLi, false);
687
+ parentLi.focus();
688
+ }
676
689
  } else if (arrowUpOrDown && this.isOpen) {
677
690
  e.preventDefault();
678
691
  const direction = Utils.keys.ARROW_DOWN.includes(e.key) ? 1 : -1;
692
+ const list = this._containingSubmenu(e) ?? this.dropdownEl;
679
693
  let newFocusedIndex = this.focusedIndex;
680
694
  let hasFoundNewIndex = false;
681
695
  do {
682
696
  newFocusedIndex = newFocusedIndex + direction;
683
- if (!!this.dropdownEl.children[newFocusedIndex] && this.dropdownEl.children[newFocusedIndex].tabIndex !== -1) {
697
+ if (!!list.children[newFocusedIndex] && list.children[newFocusedIndex].tabIndex !== -1) {
684
698
  hasFoundNewIndex = true;
685
699
  break;
686
700
  }
687
- } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0);
701
+ } while (newFocusedIndex < list.children.length && newFocusedIndex >= 0);
688
702
  if (hasFoundNewIndex) {
689
703
  if (this.focusedIndex >= 0)
690
- this.dropdownEl.children[this.focusedIndex].classList.remove("active");
704
+ list.children[this.focusedIndex]?.classList.remove("active");
691
705
  this.focusedIndex = newFocusedIndex;
692
- this._focusFocusedItem();
706
+ const item = list.children[this.focusedIndex];
707
+ item.classList.add("active");
708
+ item.focus({ preventScroll: true });
693
709
  }
694
710
  } else if (Utils.keys.ENTER.includes(e.key) && this.isOpen) {
695
- const focusedElement = this.dropdownEl.children[this.focusedIndex];
711
+ const li = this._focusedRow(e);
712
+ if (li?.querySelector(":scope > menu")) {
713
+ e.preventDefault();
714
+ this._toggleSubmenu(li);
715
+ return;
716
+ }
717
+ const focusedElement = li ?? this.dropdownEl.children[this.focusedIndex];
696
718
  const activatableElement = focusedElement?.querySelector("a, button");
697
719
  if (!!activatableElement) {
698
720
  activatableElement.click();
699
- } else if (!!focusedElement) {
700
- if (focusedElement instanceof HTMLElement) {
701
- focusedElement.click();
702
- }
721
+ } else if (focusedElement instanceof HTMLElement) {
722
+ focusedElement.click();
703
723
  }
704
724
  } else if (Utils.keys.ESC.includes(e.key) && this.isOpen) {
705
725
  e.preventDefault();
706
- this.close();
726
+ const openSub = this.dropdownEl.querySelector("li.open");
727
+ if (openSub) {
728
+ openSub.classList.remove("open", "submenu-start");
729
+ this._syncSubmenuAria(openSub, false);
730
+ openSub.focus();
731
+ } else {
732
+ this.close();
733
+ }
707
734
  }
708
735
  const keyText = e.key.toLowerCase();
709
736
  const isLetter = /[a-zA-Z0-9-_]/.test(keyText);
@@ -717,7 +744,8 @@ var _Dropdown = class _Dropdown extends Component {
717
744
  if (isLetter && !specialKeys.includes(e.key)) {
718
745
  this.filterQuery.push(keyText);
719
746
  const string = this.filterQuery.join("");
720
- const newOptionEl = Array.from(this.dropdownEl.querySelectorAll("li")).find(
747
+ const list = this._containingSubmenu(e) ?? this.dropdownEl;
748
+ const newOptionEl = Array.from(list.querySelectorAll(":scope > li")).find(
721
749
  (el) => el.textContent.trim().toLowerCase().indexOf(string) === 0
722
750
  );
723
751
  if (newOptionEl) {
@@ -759,6 +787,7 @@ var _Dropdown = class _Dropdown extends Component {
759
787
  if (!this.isOpen) return;
760
788
  this.isOpen = false;
761
789
  this.focusedIndex = -1;
790
+ this._closeSubmenus();
762
791
  if (typeof this.options.onCloseStart === "function") {
763
792
  this.options.onCloseStart.call(this, this.el);
764
793
  }
@@ -782,7 +811,6 @@ var _Dropdown = class _Dropdown extends Component {
782
811
  _Dropdown._dropdowns.push(this);
783
812
  this.id = Utils.getIdFromTrigger(el);
784
813
  this.dropdownEl = document.getElementById(this.id);
785
- this.dropdownEl?.classList.add("dropdown-content");
786
814
  this.options = {
787
815
  ..._Dropdown.defaults,
788
816
  ...options
@@ -795,6 +823,7 @@ var _Dropdown = class _Dropdown extends Component {
795
823
  this.el.ariaExpanded = "false";
796
824
  this._moveDropdownToElement();
797
825
  this._makeDropdownFocusable();
826
+ this._setupSubmenus();
798
827
  this._setupEventHandlers();
799
828
  }
800
829
  static get defaults() {
@@ -823,6 +852,9 @@ var _Dropdown = class _Dropdown extends Component {
823
852
  _setupEventHandlers() {
824
853
  this.el.addEventListener("keydown", this._handleTriggerKeydown);
825
854
  this.dropdownEl?.addEventListener("click", this._handleDropdownClick);
855
+ if (this.dropdownEl?.querySelector(":scope > li > menu")) {
856
+ this.dropdownEl.addEventListener("mouseover", this._handleSubmenuAlign);
857
+ }
826
858
  if (this.options.hover) {
827
859
  this.el.addEventListener("mouseenter", this._handleMouseEnter);
828
860
  this.el.addEventListener("mouseleave", this._handleMouseLeave);
@@ -834,6 +866,7 @@ var _Dropdown = class _Dropdown extends Component {
834
866
  _removeEventHandlers() {
835
867
  this.el.removeEventListener("keydown", this._handleTriggerKeydown);
836
868
  this.dropdownEl?.removeEventListener("click", this._handleDropdownClick);
869
+ this.dropdownEl?.removeEventListener("mouseover", this._handleSubmenuAlign);
837
870
  if (this.options.hover) {
838
871
  this.el.removeEventListener("mouseenter", this._handleMouseEnter);
839
872
  this.el.removeEventListener("mouseleave", this._handleMouseLeave);
@@ -854,6 +887,68 @@ var _Dropdown = class _Dropdown extends Component {
854
887
  this.dropdownEl?.removeEventListener("keydown", this._handleDropdownKeydown);
855
888
  window.removeEventListener("resize", this._handleWindowResize);
856
889
  }
890
+ _isSubmenuTriggerClick(target) {
891
+ if (!this.dropdownEl) return false;
892
+ const li = target.closest("li");
893
+ if (!li || !this.dropdownEl.contains(li)) return false;
894
+ const submenu = li.querySelector(":scope > menu");
895
+ if (!submenu) return false;
896
+ return !submenu.contains(target);
897
+ }
898
+ _setupSubmenus() {
899
+ this.dropdownEl?.querySelectorAll("li").forEach((li) => {
900
+ if (!li.querySelector(":scope > menu")) return;
901
+ const trigger = li.querySelector(":scope > a, :scope > button, :scope > span") ?? li;
902
+ trigger.setAttribute("aria-haspopup", "menu");
903
+ trigger.setAttribute("aria-expanded", "false");
904
+ });
905
+ }
906
+ _toggleSubmenu(li) {
907
+ const open = !li.classList.contains("open");
908
+ li.parentElement?.querySelectorAll(":scope > li.open").forEach((other) => {
909
+ if (other !== li) {
910
+ other.classList.remove("open", "submenu-start");
911
+ this._syncSubmenuAria(other, false);
912
+ }
913
+ });
914
+ li.classList.toggle("open", open);
915
+ if (open) this._alignSubmenu(li);
916
+ this._syncSubmenuAria(li, open);
917
+ }
918
+ _syncSubmenuAria(li, open) {
919
+ const trigger = li.querySelector(":scope > a, :scope > button, :scope > span") ?? li;
920
+ trigger.setAttribute("aria-expanded", open ? "true" : "false");
921
+ }
922
+ _alignSubmenu(li) {
923
+ const menu = li.querySelector(":scope > menu");
924
+ if (!menu) return;
925
+ const wasHidden = getComputedStyle(menu).display === "none";
926
+ if (wasHidden) menu.style.display = "block";
927
+ li.classList.remove("submenu-start");
928
+ const rect = menu.getBoundingClientRect();
929
+ if (rect.right > window.innerWidth - 8) li.classList.add("submenu-start");
930
+ if (wasHidden) menu.style.display = "";
931
+ }
932
+ _closeSubmenus() {
933
+ this.dropdownEl?.querySelectorAll("li.open").forEach((li) => {
934
+ li.classList.remove("open", "submenu-start");
935
+ this._syncSubmenuAria(li, false);
936
+ });
937
+ }
938
+ _containingSubmenu(e) {
939
+ const target = e.target;
940
+ if (!(target instanceof Element)) return null;
941
+ const submenu = target.closest("li > menu");
942
+ if (submenu instanceof HTMLElement && this.dropdownEl?.contains(submenu)) return submenu;
943
+ return null;
944
+ }
945
+ _focusedRow(e) {
946
+ const target = e.target;
947
+ if (!(target instanceof Element)) return null;
948
+ const li = target.closest("li");
949
+ if (li instanceof HTMLElement && this.dropdownEl?.contains(li)) return li;
950
+ return null;
951
+ }
857
952
  _resetDropdownStyles() {
858
953
  this.dropdownEl.style.display = "";
859
954
  this._resetDropdownPositioningStyles();
@@ -882,7 +977,7 @@ var _Dropdown = class _Dropdown extends Component {
882
977
  if (!this.dropdownEl) return;
883
978
  this.dropdownEl.popover = "";
884
979
  this.dropdownEl.tabIndex = 0;
885
- Array.from(this.dropdownEl.children).forEach((el) => {
980
+ this.dropdownEl.querySelectorAll(":scope li, :scope > hr").forEach((el) => {
886
981
  if (el instanceof HTMLHRElement || el.classList.contains("divider")) {
887
982
  el.setAttribute("tabindex", "-1");
888
983
  return;
@@ -1230,10 +1325,10 @@ var _Autocomplete = class _Autocomplete extends Component {
1230
1325
  }
1231
1326
  }
1232
1327
  _setupDropdown() {
1233
- this.container = document.createElement("ul");
1328
+ this.container = document.createElement("menu");
1234
1329
  this.container.style.maxHeight = this.options.maxDropDownHeight;
1235
1330
  this.container.id = `autocomplete-options-${Utils.guid()}`;
1236
- this.container.classList.add("autocomplete-content", "dropdown-content");
1331
+ this.container.classList.add("autocomplete-content");
1237
1332
  this.container.ariaExpanded = "true";
1238
1333
  this.el.setAttribute("data-target", this.container.id);
1239
1334
  this.menuItems.forEach((menuItem) => {
@@ -1414,19 +1509,6 @@ var _Autocomplete = class _Autocomplete extends Component {
1414
1509
  this._updateSelectedInfo();
1415
1510
  this._triggerChanged();
1416
1511
  }
1417
- /**
1418
- * Sets selected values.
1419
- * @deprecated @see https://github.com/materializecss/materialize/issues/552
1420
- * @param entries
1421
- */
1422
- setValues(entries) {
1423
- this.selectedValues = entries;
1424
- this._updateSelectedInfo();
1425
- if (!this.options.isMultiSelect) {
1426
- this._refreshInputText();
1427
- }
1428
- this._triggerChanged();
1429
- }
1430
1512
  /**
1431
1513
  * Select a specific autocomplete option via id-property.
1432
1514
  * @param id The id of a data-entry.
@@ -1452,14 +1534,6 @@ var _Autocomplete = class _Autocomplete extends Component {
1452
1534
  this._updateSelectedInfo();
1453
1535
  this._triggerChanged();
1454
1536
  }
1455
- selectOptions(ids) {
1456
- const entries = this.menuItems.filter(
1457
- (item) => !(ids.indexOf(item.id) === -1)
1458
- );
1459
- if (!entries) return;
1460
- this.selectedValues = entries;
1461
- this._renderDropdown();
1462
- }
1463
1537
  };
1464
1538
  /**
1465
1539
  * The three-dot loading indicator, parsed once and cloned thereafter.
@@ -1539,7 +1613,7 @@ var _Chips = class _Chips extends Component {
1539
1613
  this._renderChips();
1540
1614
  }
1541
1615
  if (this.options.allowUserInput) {
1542
- this.el.classList.add("input-field");
1616
+ this.el.classList.add("field");
1543
1617
  this._setupInput();
1544
1618
  this._setupEventHandlers();
1545
1619
  this.el.append(this._input);
@@ -2403,7 +2477,7 @@ var _Carousel = class _Carousel extends Component {
2403
2477
  ..._Carousel.defaults,
2404
2478
  ...options
2405
2479
  };
2406
- this._flat = this.options.fullWidth || this.el.classList.contains("flat") || this.el.classList.contains("carousel-slider");
2480
+ this._flat = this.options.fullWidth || this.el.classList.contains("flat");
2407
2481
  if (this._flat) {
2408
2482
  this.el.classList.add("flat");
2409
2483
  this.options.fullWidth = true;
@@ -2870,9 +2944,7 @@ var _defaults9 = {
2870
2944
  onOpenStart: null,
2871
2945
  onOpenEnd: null,
2872
2946
  onCloseStart: null,
2873
- onCloseEnd: null,
2874
- inDuration: 300,
2875
- outDuration: 300
2947
+ onCloseEnd: null
2876
2948
  };
2877
2949
  var Collapsible = class _Collapsible extends Component {
2878
2950
  constructor(el, options) {
@@ -2903,31 +2975,6 @@ var Collapsible = class _Collapsible extends Component {
2903
2975
  if (!item || !this._isOpen(item)) return;
2904
2976
  this._setOpen(item, false);
2905
2977
  };
2906
- this._handleClick = (e) => {
2907
- const header = e.target.closest(".collapsible-header");
2908
- if (!header || header.closest(".collapsible") !== this.el) return;
2909
- if (header.closest("details")) return;
2910
- const item = header.closest("li");
2911
- if (!item) return;
2912
- const index = this._items.indexOf(item);
2913
- if (index < 0) return;
2914
- if (this._isOpen(item)) this.close(index);
2915
- else this.open(index);
2916
- };
2917
- this._handleKeydown = (e) => {
2918
- if (!Utils.keys.ENTER.includes(e.key) && e.key !== " ") return;
2919
- const header = e.target.closest(".collapsible-header");
2920
- if (!header || header.closest(".collapsible") !== this.el) return;
2921
- if (header.closest("details")) return;
2922
- if (header.matches("a, button")) return;
2923
- e.preventDefault();
2924
- const item = header.closest("li");
2925
- if (!item) return;
2926
- const index = this._items.indexOf(item);
2927
- if (index < 0) return;
2928
- if (this._isOpen(item)) this.close(index);
2929
- else this.open(index);
2930
- };
2931
2978
  this._handleToggle = (e) => {
2932
2979
  const item = e.target;
2933
2980
  if (!(item instanceof HTMLDetailsElement)) return;
@@ -2969,9 +3016,7 @@ var Collapsible = class _Collapsible extends Component {
2969
3016
  this.el["Expressive_Collapsible"] = void 0;
2970
3017
  }
2971
3018
  _collectItems() {
2972
- const details = Array.from(this.el.querySelectorAll(":scope > details"));
2973
- if (details.length) return details;
2974
- return Array.from(this.el.children).filter((c) => c.tagName === "LI");
3019
+ return Array.from(this.el.querySelectorAll(":scope > details"));
2975
3020
  }
2976
3021
  _setupItems() {
2977
3022
  if (this.options.accordion) {
@@ -2985,36 +3030,26 @@ var Collapsible = class _Collapsible extends Component {
2985
3030
  if (this.options.accordion && opened.length > 1) {
2986
3031
  opened.slice(1).forEach((item) => {
2987
3032
  if (item instanceof HTMLDetailsElement) item.open = false;
2988
- else item.classList.remove("active");
2989
3033
  });
2990
3034
  }
2991
- this._items.forEach((item) => this._syncAria(item));
2992
3035
  }
2993
3036
  _isOpen(item) {
2994
- if (item instanceof HTMLDetailsElement) return item.open;
2995
- return item.classList.contains("active");
3037
+ return item instanceof HTMLDetailsElement && item.open;
2996
3038
  }
2997
3039
  _setOpen(item, open) {
2998
- if (item instanceof HTMLDetailsElement) {
2999
- item.open = open;
3000
- return;
3001
- }
3002
- item.classList.toggle("active", open);
3003
- this._syncAria(item);
3004
- this._notify(item, open);
3005
- }
3006
- _headerOf(item) {
3007
- if (item instanceof HTMLDetailsElement) {
3008
- return item.querySelector(":scope > summary");
3009
- }
3010
- return item.querySelector(":scope > .collapsible-header");
3040
+ if (item instanceof HTMLDetailsElement) item.open = open;
3011
3041
  }
3012
3042
  _wrapDetailsBodies() {
3013
3043
  this._items.forEach((item) => {
3014
3044
  if (!(item instanceof HTMLDetailsElement)) return;
3015
- if (item.querySelector(":scope > .collapsible-body")) 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
+ }
3016
3052
  const body = document.createElement("div");
3017
- body.className = "collapsible-body";
3018
3053
  Array.from(item.childNodes).forEach((node) => {
3019
3054
  if (node instanceof HTMLElement && node.tagName === "SUMMARY") return;
3020
3055
  body.appendChild(node);
@@ -3033,31 +3068,12 @@ var Collapsible = class _Collapsible extends Component {
3033
3068
  this._wrappedBodies = [];
3034
3069
  }
3035
3070
  _bodyOf(item) {
3036
- return item.querySelector(":scope > .collapsible-body");
3037
- }
3038
- _syncAria(item) {
3039
- if (item instanceof HTMLDetailsElement) return;
3040
- const header = this._headerOf(item);
3041
- const body = this._bodyOf(item);
3042
- if (!header) return;
3043
- header.setAttribute("aria-expanded", String(this._isOpen(item)));
3044
- if (body) {
3045
- if (!body.id) body.id = `collapsible-body-${Utils.guid()}`;
3046
- header.setAttribute("aria-controls", body.id);
3047
- }
3048
- if (!header.matches("a, button, summary")) {
3049
- header.setAttribute("role", "button");
3050
- if (header.tabIndex < 0) header.tabIndex = 0;
3051
- }
3071
+ return item.querySelector(":scope > :not(summary)");
3052
3072
  }
3053
3073
  _setupEventHandlers() {
3054
- this.el.addEventListener("click", this._handleClick);
3055
- this.el.addEventListener("keydown", this._handleKeydown);
3056
3074
  this.el.addEventListener("toggle", this._handleToggle, true);
3057
3075
  }
3058
3076
  _removeEventHandlers() {
3059
- this.el.removeEventListener("click", this._handleClick);
3060
- this.el.removeEventListener("keydown", this._handleKeydown);
3061
3077
  this.el.removeEventListener("toggle", this._handleToggle, true);
3062
3078
  }
3063
3079
  _notify(item, opening) {
@@ -3112,6 +3128,12 @@ var FormSelect = class _FormSelect extends Component {
3112
3128
  this._selectOptionElement(virtualOption);
3113
3129
  e.stopPropagation();
3114
3130
  };
3131
+ this._handleOptionFocus = (e) => {
3132
+ const target = e.target;
3133
+ if (!(target instanceof Element)) return;
3134
+ const li = target.closest('li[role="option"]');
3135
+ if (li?.id) this.input.setAttribute("aria-activedescendant", li.id);
3136
+ };
3115
3137
  this._handleInputClick = () => {
3116
3138
  if (this.dropdown && this.dropdown.isOpen) {
3117
3139
  this._setValueToInput();
@@ -3128,6 +3150,8 @@ var FormSelect = class _FormSelect extends Component {
3128
3150
  this.nativeTabIndex = this.el.tabIndex ?? -1;
3129
3151
  this.el.tabIndex = -1;
3130
3152
  this._values = [];
3153
+ this._createdWrapper = false;
3154
+ this._originalLabelFor = null;
3131
3155
  this._setupDropdown();
3132
3156
  this._setupEventHandlers();
3133
3157
  }
@@ -3149,6 +3173,7 @@ var FormSelect = class _FormSelect extends Component {
3149
3173
  this._removeEventHandlers();
3150
3174
  this.dropdown?.destroy();
3151
3175
  this._removeDropdown();
3176
+ this.el.tabIndex = this.nativeTabIndex;
3152
3177
  this.el["Expressive_FormSelect"] = void 0;
3153
3178
  }
3154
3179
  /**
@@ -3156,27 +3181,38 @@ var FormSelect = class _FormSelect extends Component {
3156
3181
  *
3157
3182
  * Assigning `select.value` from script fires no `change` event, so nothing
3158
3183
  * else syncs the visible input text or the `.selected` state on the virtual
3159
- * options. Call this after mutating the underlying select programmatically.
3184
+ * 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.
3160
3186
  */
3161
3187
  refresh() {
3188
+ if (!this.dropdownOptions) return;
3189
+ this._rebuildOptions();
3162
3190
  this._setValueToInput();
3163
3191
  this._setSelectedStates();
3164
3192
  }
3165
3193
  _setupEventHandlers() {
3166
- this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3167
- el.addEventListener("click", this._handleOptionClick);
3168
- el.addEventListener("keydown", this._handleOptionKeydown);
3169
- });
3194
+ this._setupOptionHandlers();
3170
3195
  this.el.addEventListener("change", this._handleSelectChange);
3171
3196
  this.input.addEventListener("click", this._handleInputClick);
3197
+ this.dropdownOptions.addEventListener("focusin", this._handleOptionFocus);
3172
3198
  }
3173
3199
  _removeEventHandlers() {
3200
+ this._removeOptionHandlers();
3201
+ this.el.removeEventListener("change", this._handleSelectChange);
3202
+ this.input?.removeEventListener("click", this._handleInputClick);
3203
+ this.dropdownOptions?.removeEventListener("focusin", this._handleOptionFocus);
3204
+ }
3205
+ _setupOptionHandlers() {
3174
3206
  this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3207
+ el.addEventListener("click", this._handleOptionClick);
3208
+ el.addEventListener("keydown", this._handleOptionKeydown);
3209
+ });
3210
+ }
3211
+ _removeOptionHandlers() {
3212
+ this.dropdownOptions?.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3175
3213
  el.removeEventListener("click", this._handleOptionClick);
3176
3214
  el.removeEventListener("keydown", this._handleOptionKeydown);
3177
3215
  });
3178
- this.el.removeEventListener("change", this._handleSelectChange);
3179
- this.input.removeEventListener("click", this._handleInputClick);
3180
3216
  }
3181
3217
  _arraysEqual(a, b) {
3182
3218
  if (a === b) return true;
@@ -3188,6 +3224,7 @@ var FormSelect = class _FormSelect extends Component {
3188
3224
  _selectOptionElement(virtualOption) {
3189
3225
  if (!virtualOption.classList.contains("disabled") && !virtualOption.classList.contains("optgroup")) {
3190
3226
  const value = this._values.find((value2) => value2.optionEl === virtualOption);
3227
+ if (!value) return;
3191
3228
  const previousSelectedValues = this.getSelectedValues();
3192
3229
  if (this.isMultiple) {
3193
3230
  this._toggleEntryFromArray(value);
@@ -3203,70 +3240,54 @@ var FormSelect = class _FormSelect extends Component {
3203
3240
  new Event("change", { bubbles: true, cancelable: true, composed: true })
3204
3241
  );
3205
3242
  }
3206
- if (!this.isMultiple) this.dropdown.close();
3243
+ if (!this.isMultiple) this.dropdown?.close();
3207
3244
  }
3208
3245
  _setupDropdown() {
3209
3246
  this.labelEl = this.el.labels?.[0] ?? null;
3210
- this.wrapper = document.createElement("div");
3211
- this.wrapper.classList.add("select-wrapper", "input-field");
3212
- if (this.options.classes.length > 0) {
3213
- this.wrapper.classList.add(...this.options.classes.split(" ").filter(Boolean));
3214
- }
3215
- this.el.before(this.wrapper);
3216
- const hiddenDiv = document.createElement("div");
3217
- hiddenDiv.classList.add("hide-select");
3218
- this.wrapper.append(hiddenDiv);
3219
- hiddenDiv.appendChild(this.el);
3247
+ this._setupWrapper();
3248
+ this._hideNativeSelect();
3220
3249
  if (this.el.disabled) this.wrapper.classList.add("disabled");
3221
- this.selectOptions = Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
3222
- this.dropdownOptions = document.createElement("ul");
3250
+ this.dropdownOptions = document.createElement("menu");
3223
3251
  this.dropdownOptions.id = `select-options-${Utils.guid()}`;
3224
3252
  this.dropdownOptions.setAttribute("popover", "auto");
3225
- this.dropdownOptions.classList.add("dropdown-content", "select-dropdown");
3226
3253
  this.dropdownOptions.setAttribute("role", "listbox");
3227
3254
  this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
3228
3255
  if (this.isMultiple) this.dropdownOptions.classList.add("multiple-select-dropdown");
3229
- if (this.selectOptions.length > 0) {
3230
- this.selectOptions.forEach((realOption) => {
3231
- if (realOption.tagName === "OPTION") {
3232
- const virtualOption = this._createAndAppendOptionWithIcon(
3233
- realOption,
3234
- this.isMultiple ? "multiple" : void 0
3235
- );
3236
- this._addOptionToValues(realOption, virtualOption);
3237
- } else if (realOption.tagName === "OPTGROUP") {
3238
- const groupId = "opt-group-" + Utils.guid();
3239
- const groupParent = document.createElement("li");
3240
- groupParent.classList.add("optgroup");
3241
- groupParent.tabIndex = -1;
3242
- groupParent.setAttribute("role", "group");
3243
- groupParent.setAttribute("aria-labelledby", groupId);
3244
- const groupLabel = document.createElement("span");
3245
- groupLabel.id = groupId;
3246
- groupLabel.setAttribute("role", "presentation");
3247
- groupLabel.textContent = realOption.getAttribute("label") ?? "";
3248
- groupParent.replaceChildren(groupLabel);
3249
- this.dropdownOptions.append(groupParent);
3250
- const groupChildren = [];
3251
- const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3252
- selectOptions.forEach((realOption2) => {
3253
- const virtualOption = this._createAndAppendOptionWithIcon(
3254
- realOption2,
3255
- "optgroup-option"
3256
- );
3257
- const childId = "opt-child-" + Utils.guid();
3258
- virtualOption.id = childId;
3259
- groupChildren.push(childId);
3260
- this._addOptionToValues(realOption2, virtualOption);
3261
- });
3262
- groupParent.setAttribute("aria-owns", groupChildren.join(" "));
3263
- }
3264
- });
3265
- }
3256
+ this._buildOptions();
3266
3257
  this.wrapper.append(this.dropdownOptions);
3258
+ this._buildInput();
3259
+ this._buildCaret();
3260
+ this._initDropdown();
3261
+ this._setSelectedStates();
3262
+ if (this.labelEl) this.input.after(this.labelEl);
3263
+ }
3264
+ _setupWrapper() {
3265
+ const parent = this.el.parentElement;
3266
+ const reuse = parent && parent.matches(".field") && !parent.querySelector(":scope > .hide-select") && !parent.querySelector(":scope > input, :scope > textarea");
3267
+ if (reuse) {
3268
+ this.wrapper = parent;
3269
+ this._createdWrapper = false;
3270
+ } else {
3271
+ this.wrapper = document.createElement("div");
3272
+ this.wrapper.classList.add("field");
3273
+ this._createdWrapper = true;
3274
+ this.el.before(this.wrapper);
3275
+ }
3276
+ if (this.options.classes.length > 0) {
3277
+ this.wrapper.classList.add(...this.options.classes.split(" ").filter(Boolean));
3278
+ }
3279
+ }
3280
+ _hideNativeSelect() {
3281
+ const hiddenDiv = document.createElement("div");
3282
+ hiddenDiv.classList.add("hide-select");
3283
+ this.el.before(hiddenDiv);
3284
+ hiddenDiv.appendChild(this.el);
3285
+ this.wrapper.append(hiddenDiv);
3286
+ }
3287
+ _buildInput() {
3267
3288
  this.input = document.createElement("input");
3268
- this.input.id = "m_select-input-" + Utils.guid();
3269
- this.input.classList.add("select-dropdown", "dropdown-trigger");
3289
+ this.input.id = "select-input-" + Utils.guid();
3290
+ this.input.classList.add("dropdown-trigger");
3270
3291
  this.input.type = "text";
3271
3292
  this.input.readOnly = true;
3272
3293
  this.input.setAttribute("data-target", this.dropdownOptions.id);
@@ -3280,71 +3301,131 @@ var FormSelect = class _FormSelect extends Component {
3280
3301
  if (attr.name.startsWith("aria-")) this.input.setAttribute(attr.name, attr.value);
3281
3302
  }
3282
3303
  this.input.setAttribute("role", "combobox");
3304
+ this.input.setAttribute("aria-haspopup", "listbox");
3283
3305
  this.input.ariaExpanded = "false";
3284
- this.input.setAttribute("aria-owns", this.dropdownOptions.id);
3285
3306
  this.input.setAttribute("aria-controls", this.dropdownOptions.id);
3286
3307
  this.input.placeholder = " ";
3308
+ if (this.labelEl) {
3309
+ this._originalLabelFor = this.labelEl.htmlFor;
3310
+ this.labelEl.htmlFor = this.input.id;
3311
+ }
3287
3312
  this.wrapper.prepend(this.input);
3288
3313
  this._setValueToInput();
3289
- const dropdownIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
3290
- dropdownIcon.classList.add("caret");
3291
- dropdownIcon.setAttribute("height", "24");
3292
- dropdownIcon.setAttribute("width", "24");
3293
- dropdownIcon.setAttribute("viewBox", "0 0 24 24");
3294
- dropdownIcon.ariaHidden = "true";
3295
- dropdownIcon.innerHTML = `<path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/>`;
3296
- this.wrapper.prepend(dropdownIcon);
3297
- if (!this.el.disabled) {
3298
- const dropdownOptions = { ...this.options.dropdownOptions };
3299
- dropdownOptions.coverTrigger = false;
3300
- const userOnOpenEnd = dropdownOptions.onOpenEnd;
3301
- const userOnCloseEnd = dropdownOptions.onCloseEnd;
3302
- dropdownOptions.onOpenEnd = () => {
3303
- const selectedOption = this.dropdownOptions.querySelector(".selected");
3304
- if (selectedOption) {
3305
- Utils.keyDown = true;
3306
- this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(
3307
- selectedOption
3308
- );
3309
- this.dropdown._focusFocusedItem();
3310
- Utils.keyDown = false;
3311
- if (this.dropdown.isScrollable) {
3312
- let scrollOffset = selectedOption.getBoundingClientRect().top - this.dropdownOptions.getBoundingClientRect().top;
3313
- scrollOffset -= this.dropdownOptions.clientHeight / 2;
3314
- this.dropdownOptions.scrollTop = scrollOffset;
3315
- }
3314
+ }
3315
+ _buildCaret() {
3316
+ const caret = document.createElement("span");
3317
+ caret.classList.add("caret");
3318
+ caret.setAttribute("aria-hidden", "true");
3319
+ this.wrapper.prepend(caret);
3320
+ }
3321
+ _initDropdown() {
3322
+ 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");
3329
+ if (selectedOption) {
3330
+ Utils.keyDown = true;
3331
+ this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
3332
+ this.dropdown._focusFocusedItem();
3333
+ 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;
3316
3338
  }
3317
- this.input.ariaExpanded = "true";
3318
- if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3319
- userOnOpenEnd.call(this.dropdown, this.el);
3320
- };
3321
- dropdownOptions.onCloseEnd = () => {
3322
- this.input.ariaExpanded = "false";
3323
- if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3324
- userOnCloseEnd.call(this.dropdown, this.el);
3325
- };
3326
- dropdownOptions.closeOnClick = false;
3327
- this.dropdown = Dropdown.init(this.input, dropdownOptions);
3328
- }
3329
- this._setSelectedStates();
3330
- if (this.labelEl) this.input.after(this.labelEl);
3339
+ if (selectedOption.id) this.input.setAttribute("aria-activedescendant", selectedOption.id);
3340
+ }
3341
+ this.input.ariaExpanded = "true";
3342
+ if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3343
+ userOnOpenEnd.call(this.dropdown, this.el);
3344
+ };
3345
+ dropdownOptions.onCloseEnd = () => {
3346
+ this.input.ariaExpanded = "false";
3347
+ this.input.removeAttribute("aria-activedescendant");
3348
+ if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3349
+ userOnCloseEnd.call(this.dropdown, this.el);
3350
+ };
3351
+ dropdownOptions.closeOnClick = false;
3352
+ this.dropdown = Dropdown.init(this.input, dropdownOptions);
3353
+ }
3354
+ _nativeOptions() {
3355
+ return Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
3356
+ }
3357
+ _buildOptions() {
3358
+ this.selectOptions = this._nativeOptions();
3359
+ this._values = [];
3360
+ this.selectOptions.forEach((realOption) => {
3361
+ if (realOption.tagName === "OPTION") {
3362
+ const virtualOption = this._createAndAppendOptionWithIcon(
3363
+ realOption,
3364
+ this.isMultiple ? "multiple" : void 0
3365
+ );
3366
+ this._addOptionToValues(realOption, virtualOption);
3367
+ } else if (realOption.tagName === "OPTGROUP") {
3368
+ const groupId = "opt-group-" + Utils.guid();
3369
+ const groupParent = document.createElement("li");
3370
+ groupParent.classList.add("optgroup");
3371
+ groupParent.tabIndex = -1;
3372
+ groupParent.setAttribute("role", "group");
3373
+ groupParent.setAttribute("aria-labelledby", groupId);
3374
+ const groupLabel = document.createElement("span");
3375
+ groupLabel.id = groupId;
3376
+ groupLabel.setAttribute("role", "presentation");
3377
+ groupLabel.textContent = realOption.getAttribute("label") ?? "";
3378
+ groupParent.replaceChildren(groupLabel);
3379
+ this.dropdownOptions.append(groupParent);
3380
+ const groupChildren = [];
3381
+ const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3382
+ selectOptions.forEach((child) => {
3383
+ const virtualOption = this._createAndAppendOptionWithIcon(child, "optgroup-option");
3384
+ groupChildren.push(virtualOption.id);
3385
+ this._addOptionToValues(child, virtualOption);
3386
+ });
3387
+ groupParent.setAttribute("aria-owns", groupChildren.join(" "));
3388
+ }
3389
+ });
3390
+ }
3391
+ _rebuildOptions() {
3392
+ this._removeOptionHandlers();
3393
+ this.dropdownOptions.replaceChildren();
3394
+ this._buildOptions();
3395
+ this._setupOptionHandlers();
3396
+ this.dropdown?._makeDropdownFocusable();
3331
3397
  }
3332
3398
  _addOptionToValues(realOption, virtualOption) {
3333
3399
  this._values.push({ el: realOption, optionEl: virtualOption });
3334
3400
  }
3335
3401
  _removeDropdown() {
3336
- this.wrapper.querySelector(".caret").remove();
3337
- this.input.remove();
3338
- this.dropdownOptions.remove();
3339
- this.wrapper.before(this.el);
3340
- this.wrapper.remove();
3402
+ this.wrapper?.querySelector(":scope > .caret")?.remove();
3403
+ this.input?.remove();
3404
+ this.dropdownOptions?.remove();
3405
+ const hide = this.el.parentElement;
3406
+ if (hide?.classList.contains("hide-select")) hide.replaceWith(this.el);
3407
+ if (this.labelEl && this._originalLabelFor !== null) {
3408
+ this.labelEl.htmlFor = this._originalLabelFor;
3409
+ }
3410
+ if (!this.wrapper) return;
3411
+ if (this._createdWrapper) {
3412
+ this.wrapper.replaceWith(this.el);
3413
+ } else {
3414
+ this.wrapper.classList.remove("disabled");
3415
+ if (this.options.classes.length > 0) {
3416
+ this.wrapper.classList.remove(...this.options.classes.split(" ").filter(Boolean));
3417
+ }
3418
+ }
3341
3419
  }
3342
3420
  _createAndAppendOptionWithIcon(realOption, type) {
3343
3421
  const li = document.createElement("li");
3422
+ li.id = "select-option-" + Utils.guid();
3344
3423
  li.setAttribute("role", "option");
3424
+ li.tabIndex = 0;
3345
3425
  if (realOption.disabled) {
3346
3426
  li.classList.add("disabled");
3347
3427
  li.ariaDisabled = "true";
3428
+ li.tabIndex = -1;
3348
3429
  }
3349
3430
  if (type === "optgroup-option") li.classList.add(type);
3350
3431
  const optionText = realOption.textContent;
@@ -3353,6 +3434,7 @@ var FormSelect = class _FormSelect extends Component {
3353
3434
  const label = document.createElement("label");
3354
3435
  const checkbox = document.createElement("input");
3355
3436
  checkbox.type = "checkbox";
3437
+ checkbox.tabIndex = -1;
3356
3438
  const labelText = document.createElement("span");
3357
3439
  labelText.textContent = optionText;
3358
3440
  label.append(checkbox, labelText);
@@ -3416,7 +3498,7 @@ var FormSelect = class _FormSelect extends Component {
3416
3498
  if (texts.length === 0) {
3417
3499
  const firstDisabledOption = this.el.querySelector("option:disabled");
3418
3500
  if (firstDisabledOption && firstDisabledOption.value === "") {
3419
- this.input.value = firstDisabledOption.innerText;
3501
+ this.input.value = firstDisabledOption.textContent;
3420
3502
  return;
3421
3503
  }
3422
3504
  }
@@ -3438,7 +3520,7 @@ var FormSelect = class _FormSelect extends Component {
3438
3520
  _activateOption(ul, li) {
3439
3521
  if (!li) return;
3440
3522
  if (!this.isMultiple)
3441
- ul.querySelectorAll("li.selected").forEach((li2) => li2.classList.remove("selected"));
3523
+ ul.querySelectorAll("li.selected").forEach((row) => row.classList.remove("selected"));
3442
3524
  li.classList.add("selected");
3443
3525
  li.ariaSelected = "true";
3444
3526
  }
@@ -3724,7 +3806,6 @@ var _Datepicker = class _Datepicker extends Component {
3724
3806
  }
3725
3807
  }
3726
3808
  };
3727
- // Set input value to the selected date and close Datepicker
3728
3809
  this._finishSelection = () => {
3729
3810
  this.setInputValues();
3730
3811
  };
@@ -4280,7 +4361,7 @@ var _Datepicker = class _Datepicker extends Component {
4280
4361
  if (opts.yearRangeReverse) arr.reverse();
4281
4362
  const yearHtml = `<select class="datepicker-select orig-select-year" tabindex="-1">${arr.join("")}</select>`;
4282
4363
  const leftArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/><path d="M0-.5h24v24H0z" fill="none"/></svg>';
4283
- html += `<button class="month-prev${prev ? "" : " is-disabled"} btn" type="button">${leftArrow}</button>`;
4364
+ html += `<button class="month-prev${prev ? "" : " is-disabled"}" type="button">${leftArrow}</button>`;
4284
4365
  html += '<div class="selects-container">';
4285
4366
  if (opts.showMonthAfterYear) {
4286
4367
  html += yearHtml + monthHtml;
@@ -4289,7 +4370,7 @@ var _Datepicker = class _Datepicker extends Component {
4289
4370
  }
4290
4371
  html += "</div>";
4291
4372
  const rightArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/><path d="M0-.25h24v24H0z" fill="none"/></svg>';
4292
- html += `<button class="month-next${next ? "" : " is-disabled"} btn" type="button">${rightArrow}</button>`;
4373
+ html += `<button class="month-next${next ? "" : " is-disabled"}" type="button">${rightArrow}</button>`;
4293
4374
  return html += "</div>";
4294
4375
  }
4295
4376
  /**
@@ -4487,17 +4568,6 @@ var _Datepicker = class _Datepicker extends Component {
4487
4568
  this.el.parentElement.appendChild(dateInput);
4488
4569
  return dateInput;
4489
4570
  }
4490
- // deprecated
4491
- open() {
4492
- console.warn("Datepicker.open() is deprecated. Remove this method and wrap in modal yourself.");
4493
- return this;
4494
- }
4495
- close() {
4496
- console.warn(
4497
- "Datepicker.close() is deprecated. Remove this method and wrap in modal yourself."
4498
- );
4499
- return this;
4500
- }
4501
4571
  };
4502
4572
  _Datepicker._template = `
4503
4573
  <div class="datepicker-container">
@@ -4507,13 +4577,7 @@ _Datepicker._template = `
4507
4577
  </div>
4508
4578
  <div class="datepicker-calendar-container">
4509
4579
  <div class="datepicker-calendar"></div>
4510
- <div class="datepicker-footer">
4511
- <!--<button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>
4512
- <div class="confirmation-btns">
4513
- <button class="btn-flat datepicker-cancel waves-effect" type="button"></button>
4514
- <button class="btn-flat datepicker-done waves-effect" type="button"></button>
4515
- </div>-->
4516
- </div>
4580
+ <div class="datepicker-footer"></div>
4517
4581
  </div>
4518
4582
  </div>`;
4519
4583
  var Datepicker = _Datepicker;
@@ -4802,91 +4866,8 @@ var Lightbox = class _Lightbox extends Component {
4802
4866
  }
4803
4867
  };
4804
4868
 
4805
- // src/ts/components/modal.ts
4806
- var _defaults14 = {
4807
- opacity: 0.5,
4808
- inDuration: 250,
4809
- outDuration: 250,
4810
- onOpenStart: null,
4811
- onOpenEnd: null,
4812
- onCloseStart: null,
4813
- onCloseEnd: null,
4814
- preventScrolling: true,
4815
- dismissible: true,
4816
- startingTop: "4%",
4817
- endingTop: "10%"
4818
- };
4819
- var _Modal_static, createHtml_fn, createHtmlElement_fn;
4820
- var _Modal = class _Modal extends Component {
4821
- constructor(el, options) {
4822
- super(el, options, _Modal);
4823
- this.el["Expressive_Modal"] = this;
4824
- this.options = {
4825
- ..._Modal.defaults,
4826
- ...options
4827
- };
4828
- this.el.tabIndex = 0;
4829
- this._setupEventHandlers();
4830
- }
4831
- static get defaults() {
4832
- return _defaults14;
4833
- }
4834
- static init(els, options = {}) {
4835
- return super.init(els, options, _Modal);
4836
- }
4837
- static getInstance(el) {
4838
- return el["Expressive_Modal"];
4839
- }
4840
- destroy() {
4841
- }
4842
- _setupEventHandlers() {
4843
- }
4844
- _removeEventHandlers() {
4845
- }
4846
- _handleTriggerClick() {
4847
- }
4848
- _handleOverlayClick() {
4849
- }
4850
- _handleModalCloseClick() {
4851
- }
4852
- _handleKeydown() {
4853
- }
4854
- _handleFocus() {
4855
- }
4856
- open() {
4857
- return this;
4858
- }
4859
- close() {
4860
- return this;
4861
- }
4862
- static create(config) {
4863
- const isServer = false;
4864
- if (isServer) return __privateMethod(this, _Modal_static, createHtml_fn).call(this, config);
4865
- return __privateMethod(this, _Modal_static, createHtmlElement_fn).call(this, config);
4866
- }
4867
- };
4868
- _Modal_static = new WeakSet();
4869
- createHtml_fn = function(config) {
4870
- const title = config.header ? `<h2>${typeof config.header === "string" ? config.header : ""}</h2>` : "";
4871
- const actions = config.footer ? `<form method="dialog">${typeof config.footer === "string" ? config.footer : ""}</form>` : "";
4872
- return `<dialog id="${config.id}">
4873
- ${title}
4874
- <div>${typeof config.content === "string" ? config.content : ""}</div>
4875
- ${actions}
4876
- </dialog>`;
4877
- };
4878
- createHtmlElement_fn = function(config) {
4879
- const dialog = document.createElement("dialog");
4880
- dialog.id = config.id;
4881
- return dialog;
4882
- };
4883
- __privateAdd(_Modal, _Modal_static);
4884
- var Modal = _Modal;
4885
-
4886
4869
  // src/ts/components/parallax.ts
4887
- var _defaults15 = {
4888
- responsiveThreshold: 0
4889
- };
4870
+ var _defaults14 = {};
4890
4871
  var Parallax = class _Parallax extends Component {
4891
4872
  constructor(el, options) {
4892
4873
  super(el, options, _Parallax);
@@ -4900,7 +4881,7 @@ var Parallax = class _Parallax extends Component {
4900
4881
  }
4901
4882
  }
4902
4883
  static get defaults() {
4903
- return _defaults15;
4884
+ return _defaults14;
4904
4885
  }
4905
4886
  static init(els, options = {}) {
4906
4887
  return super.init(els, options, _Parallax);
@@ -4914,7 +4895,7 @@ var Parallax = class _Parallax extends Component {
4914
4895
  };
4915
4896
 
4916
4897
  // src/ts/components/pushpin.ts
4917
- var _defaults16 = {
4898
+ var _defaults15 = {
4918
4899
  top: 0,
4919
4900
  bottom: Infinity,
4920
4901
  offset: 0,
@@ -4934,7 +4915,7 @@ var _Pushpin = class _Pushpin extends Component {
4934
4915
  this._updatePosition();
4935
4916
  }
4936
4917
  static get defaults() {
4937
- return _defaults16;
4918
+ return _defaults15;
4938
4919
  }
4939
4920
  /**
4940
4921
  * Initializes instances of Pushpin.
@@ -5003,16 +4984,12 @@ _Pushpin._pushpins = [];
5003
4984
  var Pushpin = _Pushpin;
5004
4985
 
5005
4986
  // src/ts/components/scrollspy.ts
5006
- var _defaults17 = {
5007
- throttle: 100,
4987
+ var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
4988
+ var _defaults16 = {
5008
4989
  scrollOffset: 200,
5009
- // offset - 200 allows elements near bottom of page to scroll
5010
4990
  activeClass: "active",
5011
- getActiveElement: (id) => {
5012
- return 'a[href="#' + id + '"]';
5013
- },
5014
- keepTopElementActive: false,
5015
- animationDuration: null
4991
+ getActiveElement: _defaultGetActiveElement,
4992
+ keepTopElementActive: false
5016
4993
  };
5017
4994
  var _ScrollSpy = class _ScrollSpy extends Component {
5018
4995
  constructor(el, options) {
@@ -5022,22 +4999,17 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5022
4999
  ..._ScrollSpy.defaults,
5023
5000
  ...options
5024
5001
  };
5002
+ this.el.style.setProperty(
5003
+ "--md-comp-scrollspy-offset",
5004
+ `${this.options.scrollOffset}px`
5005
+ );
5025
5006
  _ScrollSpy._elements.push(this);
5026
- _ScrollSpy._count++;
5027
- _ScrollSpy._increment++;
5028
- this.tickId = -1;
5029
- this.id = _ScrollSpy._increment.toString();
5030
- this._setupEventHandlers();
5031
- _ScrollSpy._handleWindowScroll();
5007
+ _ScrollSpy._ensureObserver(this.options.scrollOffset);
5008
+ _ScrollSpy._observer?.observe(this.el);
5032
5009
  }
5033
5010
  static get defaults() {
5034
- return _defaults17;
5011
+ return _defaults16;
5035
5012
  }
5036
- /**
5037
- * Initializes instances of ScrollSpy.
5038
- * @param els HTML elements.
5039
- * @param options Component options.
5040
- */
5041
5013
  static init(els, options = {}) {
5042
5014
  return super.init(els, options, _ScrollSpy);
5043
5015
  }
@@ -5045,348 +5017,233 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5045
5017
  return el["Expressive_ScrollSpy"];
5046
5018
  }
5047
5019
  destroy() {
5048
- const elementIndex = _ScrollSpy._elements.indexOf(this);
5049
- if (elementIndex >= 0) _ScrollSpy._elements.splice(elementIndex, 1);
5050
- const inViewIndex = _ScrollSpy._elementsInView.indexOf(this);
5051
- if (inViewIndex >= 0) _ScrollSpy._elementsInView.splice(inViewIndex, 1);
5052
- const visibleIndex = _ScrollSpy._visibleElements.indexOf(this.el);
5053
- if (visibleIndex >= 0) _ScrollSpy._visibleElements.splice(visibleIndex, 1);
5054
- _ScrollSpy._count--;
5055
- this._removeEventHandlers();
5056
- const actElem = document.querySelector(this.options.getActiveElement(this.el.id));
5057
- actElem?.classList.remove(this.options.activeClass);
5058
- this.el["Expressive_ScrollSpy"] = void 0;
5059
- }
5060
- _setupEventHandlers() {
5061
- if (_ScrollSpy._count === 1) {
5062
- _ScrollSpy._throttledScroll = Utils.throttle(_ScrollSpy._handleWindowScroll, this.options.throttle);
5063
- _ScrollSpy._throttledResize = Utils.throttle(_ScrollSpy._handleWindowScroll, 200);
5064
- window.addEventListener("scroll", _ScrollSpy._throttledScroll, { passive: true });
5065
- window.addEventListener("resize", _ScrollSpy._throttledResize, { passive: true });
5066
- document.body.addEventListener("click", _ScrollSpy._handleTriggerClick);
5067
- }
5068
- }
5069
- _removeEventHandlers() {
5070
- if (_ScrollSpy._count === 0) {
5071
- window.removeEventListener("scroll", _ScrollSpy._throttledScroll);
5072
- window.removeEventListener("resize", _ScrollSpy._throttledResize);
5073
- document.body.removeEventListener("click", _ScrollSpy._handleTriggerClick);
5074
- _ScrollSpy._throttledScroll = null;
5075
- _ScrollSpy._throttledResize = null;
5020
+ const index = _ScrollSpy._elements.indexOf(this);
5021
+ if (index >= 0) _ScrollSpy._elements.splice(index, 1);
5022
+ _ScrollSpy._ratios.delete(this.el);
5023
+ _ScrollSpy._observer?.unobserve(this.el);
5024
+ const link = _ScrollSpy._linkFor(this.el.id, this.options);
5025
+ if (link && link === _ScrollSpy._active) {
5026
+ _ScrollSpy._clearActive(this.options);
5027
+ } else {
5028
+ link?.classList.remove(this.options.activeClass);
5029
+ link?.removeAttribute("aria-current");
5030
+ }
5031
+ if (_ScrollSpy._elements.length === 0) {
5032
+ _ScrollSpy._observer?.disconnect();
5033
+ _ScrollSpy._observer = null;
5034
+ _ScrollSpy._ratios.clear();
5035
+ _ScrollSpy._active = null;
5036
+ } else {
5037
+ _ScrollSpy._syncActive();
5076
5038
  }
5039
+ this.el["Expressive_ScrollSpy"] = void 0;
5077
5040
  }
5078
- static _findElements(top, right, bottom, left) {
5079
- const hits = [];
5080
- const docElem = document.documentElement;
5081
- const clientTop = docElem.clientTop;
5082
- const clientLeft = docElem.clientLeft;
5083
- const scrollY = window.scrollY;
5084
- const scrollX = window.scrollX;
5085
- for (let i = 0; i < _ScrollSpy._elements.length; i++) {
5086
- const scrollspy = _ScrollSpy._elements[i];
5087
- const currTop = top + scrollspy.options.scrollOffset || 200;
5088
- const box = scrollspy.el.getBoundingClientRect();
5089
- if (box.height > 0) {
5090
- const elTop = box.top + scrollY - clientTop, elLeft = box.left + scrollX - clientLeft, elRight = elLeft + box.width, elBottom = elTop + box.height;
5091
- const isIntersect = !(elLeft > right || elRight < left || elTop > bottom || elBottom < currTop);
5092
- if (isIntersect) {
5093
- hits.push(scrollspy);
5094
- }
5095
- }
5096
- }
5097
- return hits;
5041
+ static _ensureObserver(offset) {
5042
+ if (_ScrollSpy._observer) return;
5043
+ if (typeof IntersectionObserver === "undefined") return;
5044
+ _ScrollSpy._observer = new IntersectionObserver(_ScrollSpy._onIntersect, {
5045
+ rootMargin: `-${offset}px 0px -45% 0px`,
5046
+ threshold: [0, 0.1, 0.25, 0.5, 0.75, 1]
5047
+ });
5098
5048
  }
5099
- _enter() {
5100
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5101
- (value) => value.getBoundingClientRect().height !== 0
5102
- );
5103
- if (_ScrollSpy._visibleElements[0]) {
5104
- const actElem = document.querySelector(
5105
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5106
- );
5107
- actElem?.classList.remove(this.options.activeClass);
5108
- if (_ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"] && this.id < _ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"].id) {
5109
- _ScrollSpy._visibleElements.unshift(this.el);
5049
+ static _syncActive() {
5050
+ if (!_ScrollSpy._elements.length) return;
5051
+ const options = _ScrollSpy._elements[0].options;
5052
+ let best = null;
5053
+ let bestRatio = 0;
5054
+ for (const spy of _ScrollSpy._elements) {
5055
+ const ratio = _ScrollSpy._ratios.get(spy.el) ?? 0;
5056
+ if (ratio > bestRatio) {
5057
+ bestRatio = ratio;
5058
+ best = spy;
5059
+ }
5060
+ }
5061
+ if (!best) {
5062
+ if (options.keepTopElementActive) {
5063
+ best = _ScrollSpy._nearestAbove() ?? _ScrollSpy._elements[0];
5110
5064
  } else {
5111
- _ScrollSpy._visibleElements.push(this.el);
5065
+ _ScrollSpy._clearActive(options);
5066
+ return;
5112
5067
  }
5113
- } else {
5114
- _ScrollSpy._visibleElements.push(this.el);
5115
5068
  }
5116
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5117
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5118
- document.querySelector(selector)?.classList.add(this.options.activeClass);
5069
+ const next = _ScrollSpy._linkFor(best.el.id, best.options);
5070
+ if (next === _ScrollSpy._active) return;
5071
+ _ScrollSpy._clearActive(options);
5072
+ if (!next) return;
5073
+ next.classList.add(best.options.activeClass);
5074
+ next.setAttribute("aria-current", "true");
5075
+ _ScrollSpy._active = next;
5119
5076
  }
5120
- _exit() {
5121
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5122
- (value) => value.getBoundingClientRect().height !== 0
5123
- );
5124
- if (_ScrollSpy._visibleElements[0]) {
5125
- const actElem = document.querySelector(
5126
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5127
- );
5128
- actElem?.classList.remove(this.options.activeClass);
5129
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter((x) => x.id != this.el.id);
5130
- if (_ScrollSpy._visibleElements[0]) {
5131
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5132
- document.querySelector(selector)?.classList.add(this.options.activeClass);
5133
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5134
- }
5135
- }
5136
- }
5137
- static _resetKeptTopActiveElement(activeClass) {
5138
- if (_ScrollSpy._keptTopActiveElement) {
5139
- _ScrollSpy._keptTopActiveElement.classList.remove(activeClass);
5140
- _ScrollSpy._keptTopActiveElement = null;
5141
- }
5142
- }
5143
- static _getDistanceToViewport(element) {
5144
- const rect = element.getBoundingClientRect();
5145
- const distance = rect.top;
5146
- return distance;
5147
- }
5148
- static _smoothScrollIntoView(element, duration = 300) {
5149
- const targetPosition = element.getBoundingClientRect().top + (window.scrollY || window.pageYOffset);
5150
- const startPosition = window.scrollY || window.pageYOffset;
5151
- const distance = targetPosition - startPosition;
5152
- const startTime = performance.now();
5153
- function scrollStep(currentTime) {
5154
- const elapsed = currentTime - startTime;
5155
- const progress = Math.min(elapsed / duration, 1);
5156
- const scrollY = startPosition + distance * progress;
5157
- if (progress < 1) {
5158
- window.scrollTo(0, scrollY);
5159
- requestAnimationFrame(scrollStep);
5160
- } else {
5161
- window.scrollTo(0, targetPosition);
5077
+ static _nearestAbove() {
5078
+ let best = null;
5079
+ let bestTop = -Infinity;
5080
+ for (const spy of _ScrollSpy._elements) {
5081
+ const top = spy.el.getBoundingClientRect().top;
5082
+ if (top <= 0 && top >= bestTop) {
5083
+ bestTop = top;
5084
+ best = spy;
5162
5085
  }
5163
5086
  }
5164
- requestAnimationFrame(scrollStep);
5087
+ return best;
5165
5088
  }
5166
- };
5167
- _ScrollSpy._keptTopActiveElement = null;
5168
- // The document-level listeners are shared by every instance, so the
5169
- // references they are registered with have to be shared too - registering
5170
- // with one instance's bound handler and unregistering with another's is a
5171
- // silent no-op that leaves the listener attached forever.
5172
- _ScrollSpy._throttledScroll = null;
5173
- _ScrollSpy._throttledResize = null;
5174
- _ScrollSpy._handleTriggerClick = (e) => {
5175
- const trigger = e.target;
5176
- for (let i = _ScrollSpy._elements.length - 1; i >= 0; i--) {
5177
- const scrollspy = _ScrollSpy._elements[i];
5178
- const x = document.querySelector('a[href="#' + scrollspy.el.id + '"]');
5179
- if (trigger === x) {
5180
- e.preventDefault();
5181
- if (scrollspy.el["Expressive_ScrollSpy"].options.animationDuration) {
5182
- _ScrollSpy._smoothScrollIntoView(
5183
- scrollspy.el,
5184
- scrollspy.el["Expressive_ScrollSpy"].options.animationDuration
5185
- );
5186
- } else {
5187
- scrollspy.el.scrollIntoView({ behavior: "smooth" });
5089
+ static _clearActive(options) {
5090
+ if (!_ScrollSpy._active) return;
5091
+ _ScrollSpy._active.classList.remove(options.activeClass);
5092
+ _ScrollSpy._active.removeAttribute("aria-current");
5093
+ _ScrollSpy._active = null;
5094
+ }
5095
+ /**
5096
+ * Default lookup compares href attributes (no interpolated selector).
5097
+ * A custom getActiveElement still returns a selector.
5098
+ */
5099
+ static _linkFor(id, options) {
5100
+ if (!id) return null;
5101
+ if (options.getActiveElement !== _defaultGetActiveElement) {
5102
+ try {
5103
+ return document.querySelector(options.getActiveElement(id));
5104
+ } catch {
5105
+ return null;
5188
5106
  }
5189
- break;
5190
5107
  }
5108
+ const href = `#${id}`;
5109
+ const links = document.querySelectorAll('a[href^="#"]');
5110
+ for (let i = 0; i < links.length; i++) {
5111
+ if (links[i].getAttribute("href") === href) return links[i];
5112
+ }
5113
+ return null;
5191
5114
  }
5192
5115
  };
5193
- _ScrollSpy._handleWindowScroll = () => {
5194
- _ScrollSpy._ticks++;
5195
- const top = Utils.getDocumentScrollTop(), left = Utils.getDocumentScrollLeft(), right = left + window.innerWidth, bottom = top + window.innerHeight;
5196
- const intersections = _ScrollSpy._findElements(top, right, bottom, left);
5197
- for (let i = 0; i < intersections.length; i++) {
5198
- const scrollspy = intersections[i];
5199
- const lastTick = scrollspy.tickId;
5200
- if (lastTick < 0) {
5201
- scrollspy._enter();
5202
- }
5203
- scrollspy.tickId = _ScrollSpy._ticks;
5204
- }
5205
- for (let i = 0; i < _ScrollSpy._elementsInView.length; i++) {
5206
- const scrollspy = _ScrollSpy._elementsInView[i];
5207
- const lastTick = scrollspy.tickId;
5208
- if (lastTick >= 0 && lastTick !== _ScrollSpy._ticks) {
5209
- scrollspy._exit();
5210
- scrollspy.tickId = -1;
5211
- }
5212
- }
5213
- _ScrollSpy._elementsInView = intersections;
5214
- if (_ScrollSpy._elements.length) {
5215
- const options = _ScrollSpy._elements[0].el["Expressive_ScrollSpy"].options;
5216
- if (options.keepTopElementActive && _ScrollSpy._visibleElements.length === 0) {
5217
- _ScrollSpy._resetKeptTopActiveElement(options.activeClass);
5218
- const topElements = _ScrollSpy._elements.map((value) => ({ value, distance: _ScrollSpy._getDistanceToViewport(value.el) })).filter((entry) => entry.distance <= 0).sort((a, b) => a.distance - b.distance).map((entry) => entry.value);
5219
- const nearestTopElement = topElements.length ? topElements[topElements.length - 1] : _ScrollSpy._elements[0];
5220
- const actElem = document.querySelector(options.getActiveElement(nearestTopElement.el.id));
5221
- actElem?.classList.add(options.activeClass);
5222
- _ScrollSpy._keptTopActiveElement = actElem;
5116
+ _ScrollSpy._elements = [];
5117
+ _ScrollSpy._observer = null;
5118
+ _ScrollSpy._ratios = /* @__PURE__ */ new Map();
5119
+ _ScrollSpy._active = null;
5120
+ _ScrollSpy._onIntersect = (entries) => {
5121
+ for (const entry of entries) {
5122
+ if (entry.isIntersecting && entry.intersectionRatio > 0) {
5123
+ _ScrollSpy._ratios.set(entry.target, entry.intersectionRatio);
5124
+ } else {
5125
+ _ScrollSpy._ratios.delete(entry.target);
5223
5126
  }
5224
5127
  }
5128
+ _ScrollSpy._syncActive();
5225
5129
  };
5226
- _ScrollSpy._elements = [];
5227
- _ScrollSpy._elementsInView = [];
5228
- _ScrollSpy._visibleElements = [];
5229
- _ScrollSpy._count = 0;
5230
- _ScrollSpy._increment = 0;
5231
- _ScrollSpy._ticks = 0;
5232
5130
  var ScrollSpy = _ScrollSpy;
5233
5131
 
5234
5132
  // src/ts/components/sidenav.ts
5235
- var _defaults18 = {
5133
+ var _defaults17 = {
5236
5134
  edge: "left",
5237
5135
  draggable: true,
5238
5136
  dragTargetWidth: "10px",
5239
- inDuration: 250,
5240
- outDuration: 200,
5241
5137
  onOpenStart: null,
5242
5138
  onOpenEnd: null,
5243
5139
  onCloseStart: null,
5244
- onCloseEnd: null,
5245
- preventScrolling: true
5140
+ onCloseEnd: null
5246
5141
  };
5142
+ var LARGE_UP = "(width >= 993px)";
5247
5143
  var _Sidenav = class _Sidenav extends Component {
5248
5144
  constructor(el, options) {
5249
5145
  super(el, options, _Sidenav);
5250
- this._handleDragTargetDrag = (e) => {
5251
- if (!this._isDraggable()) return;
5252
- let totalDeltaX = this._calculateDelta(e);
5253
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5254
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5255
- if (this.options.edge === dragDirection) {
5256
- totalDeltaX = 0;
5257
- }
5258
- let transformX = totalDeltaX;
5259
- let transformPrefix = "translateX(-100%)";
5260
- if (this.options.edge === "right") {
5261
- transformPrefix = "translateX(100%)";
5262
- transformX = -transformX;
5263
- }
5264
- this.percentOpen = Math.min(1, totalDeltaX / this._width);
5265
- this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
5266
- this._overlay.style.opacity = this.percentOpen.toString();
5267
- };
5268
- this._handleDragTargetRelease = () => {
5269
- if (this.isDragged) {
5270
- if (this.percentOpen > 0.2) {
5271
- this.open();
5272
- } else {
5273
- this._animateOut();
5146
+ /**
5147
+ * Opens the overlay drawer. No-op while the sidenav is docked
5148
+ * (sidenav-fixed at the large breakpoint).
5149
+ */
5150
+ this.open = () => {
5151
+ if (this._isCurrentlyFixed() || this.isOpen || !this._dialog) return;
5152
+ _Sidenav._sidenavs.forEach((other) => {
5153
+ if (other !== this && other.isOpen) other.close();
5154
+ });
5155
+ if (typeof this.options.onOpenStart === "function") {
5156
+ this.options.onOpenStart.call(this, this.el);
5157
+ }
5158
+ this.isOpen = true;
5159
+ this._dialog.classList.remove("dragging");
5160
+ this._clearShift();
5161
+ if (!this._dialog.open) {
5162
+ try {
5163
+ this._dialog.showModal();
5164
+ } catch {
5274
5165
  }
5275
- this.isDragged = false;
5276
- this._verticallyScrolling = false;
5277
5166
  }
5278
- };
5279
- this._handleCloseDrag = (e) => {
5280
- if (!this.isOpen || !this._isDraggable()) return;
5281
- let totalDeltaX = this._calculateDelta(e);
5282
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5283
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5284
- if (this.options.edge !== dragDirection) {
5285
- totalDeltaX = 0;
5167
+ this._syncTriggers();
5168
+ if (typeof this.options.onOpenEnd === "function") {
5169
+ this.options.onOpenEnd.call(this, this.el);
5286
5170
  }
5287
- let transformX = -totalDeltaX;
5288
- if (this.options.edge === "right") {
5289
- transformX = -transformX;
5171
+ };
5172
+ /**
5173
+ * Closes the overlay drawer. No-op while the sidenav is docked.
5174
+ */
5175
+ this.close = () => {
5176
+ if (this._isCurrentlyFixed() || !this.isOpen) return;
5177
+ this._beginClose();
5178
+ if (this._dialog?.open) {
5179
+ this._closing = true;
5180
+ this._dialog.close();
5181
+ } else {
5182
+ this._finishClose();
5290
5183
  }
5291
- this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
5292
- this.el.style.transform = `translateX(${transformX}px)`;
5293
- this._overlay.style.opacity = this.percentOpen.toString();
5294
5184
  };
5295
- this._calculateDelta = (e) => {
5296
- if (!this.isDragged) {
5297
- this._startDrag(e);
5185
+ this._onDialogClose = () => {
5186
+ if (this.isOpen) {
5187
+ this._beginClose();
5188
+ this._finishClose();
5189
+ return;
5190
+ }
5191
+ if (this._closing) {
5192
+ this._closing = false;
5193
+ this._finishClose();
5298
5194
  }
5299
- this._dragMoveUpdate(e);
5300
- return this._xPos - this._startingXpos;
5301
5195
  };
5302
- this._handleCloseRelease = () => {
5303
- if (this.isOpen && this.isDragged) {
5304
- if (this.percentOpen > 0.8) {
5305
- this._animateIn();
5306
- } else {
5307
- this.close();
5308
- }
5309
- this.isDragged = false;
5310
- this._verticallyScrolling = false;
5196
+ this._onBreakpointChange = () => {
5197
+ if (this._isCurrentlyFixed() && this.isOpen) {
5198
+ this.close();
5311
5199
  }
5312
5200
  };
5313
- // Handles closing of Sidenav when element with class .sidenav-close
5314
5201
  this._handleCloseTriggerClick = (e) => {
5315
- const closeTrigger = e.target.closest(".sidenav-close");
5202
+ const target = e.target;
5203
+ if (!(target instanceof Element)) return;
5204
+ const closeTrigger = target.closest(".sidenav-close");
5316
5205
  if (closeTrigger && !this._isCurrentlyFixed()) {
5317
5206
  this.close();
5318
5207
  }
5319
5208
  };
5320
- this._handleWindowResize = () => {
5321
- if (this.lastWindowWidth !== window.innerWidth) {
5322
- if (window.innerWidth > 992) {
5323
- this.open();
5324
- } else {
5325
- this.close();
5326
- }
5327
- }
5328
- this.lastWindowWidth = window.innerWidth;
5329
- this.lastWindowHeight = window.innerHeight;
5209
+ this._handleDragTargetDrag = (e) => {
5210
+ if (!this._isDraggable()) return;
5211
+ const delta = this._rawDelta(e);
5212
+ const towardOpen = this.options.edge === "left" ? delta : -delta;
5213
+ const visible = Math.min(this._width, Math.max(0, towardOpen));
5214
+ const percentOpen = this._width ? visible / this._width : 0;
5215
+ this._applyShift(visible - this._width, percentOpen);
5330
5216
  };
5331
- /**
5332
- * Opens Sidenav.
5333
- */
5334
- this.open = () => {
5335
- if (this.isOpen === true) return;
5336
- this.isOpen = true;
5337
- if (typeof this.options.onOpenStart === "function") {
5338
- this.options.onOpenStart.call(this, this.el);
5339
- }
5340
- if (this._isCurrentlyFixed()) {
5341
- this.el.style.transform = "translateX(0)";
5342
- this._enableBodyScrolling();
5343
- this._overlay.style.display = "none";
5344
- } else {
5345
- if (this.options.preventScrolling) this._preventBodyScrolling();
5346
- if (!this.isDragged || this.percentOpen != 1) this._animateIn();
5347
- this._setAriaHidden();
5348
- this._setTabIndex();
5217
+ this._handleDragTargetRelease = () => {
5218
+ if (!this.isDragged) return;
5219
+ this._dialog?.classList.remove("dragging");
5220
+ if (this.percentOpen > 0.2) {
5221
+ this.open();
5222
+ } else if (this._dialog?.open && !this.isOpen) {
5223
+ this._clearShift();
5224
+ this._dialog.close();
5349
5225
  }
5226
+ this.isDragged = false;
5227
+ this._verticallyScrolling = false;
5350
5228
  };
5351
- /**
5352
- * Closes Sidenav.
5353
- */
5354
- this.close = () => {
5355
- if (this.isOpen === false) return;
5356
- this.isOpen = false;
5357
- if (typeof this.options.onCloseStart === "function") {
5358
- this.options.onCloseStart.call(this, this.el);
5359
- }
5360
- if (this._isCurrentlyFixed()) {
5361
- const transformX = this.options.edge === "left" ? "-105%" : "105%";
5362
- this.el.style.transform = `translateX(${transformX})`;
5229
+ this._handleCloseDrag = (e) => {
5230
+ if (!this.isOpen || !this._isDraggable()) return;
5231
+ const delta = this._rawDelta(e);
5232
+ const towardClose = this.options.edge === "left" ? -delta : delta;
5233
+ const hidden = Math.min(this._width, Math.max(0, towardClose));
5234
+ const percentOpen = this._width ? 1 - hidden / this._width : 1;
5235
+ this._applyShift(-hidden, percentOpen);
5236
+ };
5237
+ this._handleCloseRelease = () => {
5238
+ if (!this.isOpen || !this.isDragged) return;
5239
+ this._dialog?.classList.remove("dragging");
5240
+ if (this.percentOpen > 0.8) {
5241
+ this._clearShift();
5363
5242
  } else {
5364
- this._enableBodyScrolling();
5365
- if (!this.isDragged || this.percentOpen != 0) {
5366
- this._animateOut();
5367
- } else {
5368
- this._overlay.style.display = "none";
5369
- }
5370
- this._setAriaHidden();
5371
- this._setTabIndex();
5243
+ this.close();
5372
5244
  }
5373
- };
5374
- this._setAriaHidden = () => {
5375
- this.el.ariaHidden = this.isOpen ? "false" : "true";
5376
- const navWrapper = document.querySelector(".nav-wrapper ul");
5377
- if (navWrapper) navWrapper.ariaHidden = this.isOpen.toString();
5378
- };
5379
- this._setTabIndex = () => {
5380
- const navLinks = document.querySelectorAll(".nav-wrapper ul li a");
5381
- const sideNavLinks = document.querySelectorAll(".sidenav li a");
5382
- if (navLinks)
5383
- navLinks.forEach((navLink) => {
5384
- navLink.tabIndex = this.isOpen ? -1 : 0;
5385
- });
5386
- if (sideNavLinks)
5387
- sideNavLinks.forEach((sideNavLink) => {
5388
- sideNavLink.tabIndex = this.isOpen ? 0 : -1;
5389
- });
5245
+ this.isDragged = false;
5246
+ this._verticallyScrolling = false;
5390
5247
  };
5391
5248
  this.el["Expressive_Sidenav"] = this;
5392
5249
  this.options = {
@@ -5397,17 +5254,26 @@ var _Sidenav = class _Sidenav extends Component {
5397
5254
  this.isOpen = false;
5398
5255
  this.isFixed = this.el.classList.contains("sidenav-fixed");
5399
5256
  this.isDragged = false;
5400
- this.lastWindowWidth = window.innerWidth;
5401
- this.lastWindowHeight = window.innerHeight;
5402
- this._createOverlay();
5257
+ this.dragTarget = null;
5258
+ this._dialog = null;
5259
+ this._createdDialog = false;
5260
+ this._closing = false;
5261
+ this.percentOpen = 0;
5262
+ this._startingXpos = 0;
5263
+ this._xPos = 0;
5264
+ this._width = 0;
5265
+ this._initialScrollTop = 0;
5266
+ this._verticallyScrolling = false;
5267
+ this._mql = window.matchMedia(LARGE_UP);
5268
+ this._setupDialog();
5403
5269
  this._createDragTarget();
5404
- this._setupEventHandlers();
5405
5270
  this._setupClasses();
5406
- this._setupFixed();
5271
+ this._setupEventHandlers();
5272
+ this._syncTriggers();
5407
5273
  _Sidenav._sidenavs.push(this);
5408
5274
  }
5409
5275
  static get defaults() {
5410
- return _defaults18;
5276
+ return _defaults17;
5411
5277
  }
5412
5278
  /**
5413
5279
  * Initializes instances of Sidenav.
@@ -5422,182 +5288,178 @@ var _Sidenav = class _Sidenav extends Component {
5422
5288
  }
5423
5289
  destroy() {
5424
5290
  this._removeEventHandlers();
5425
- this._enableBodyScrolling();
5426
- this._overlay.parentNode.removeChild(this._overlay);
5427
- this.dragTarget.parentNode.removeChild(this.dragTarget);
5291
+ if (this._dialog?.open) {
5292
+ try {
5293
+ this._dialog.close();
5294
+ } catch {
5295
+ }
5296
+ }
5297
+ this._clearShift();
5298
+ this._unwrapDialog();
5299
+ this._removeDragTarget();
5428
5300
  this.el["Expressive_Sidenav"] = void 0;
5429
- this.el.style.transform = "";
5430
5301
  const index = _Sidenav._sidenavs.indexOf(this);
5431
5302
  if (index >= 0) {
5432
5303
  _Sidenav._sidenavs.splice(index, 1);
5433
5304
  }
5434
5305
  }
5435
- _createOverlay() {
5436
- this._overlay = document.createElement("div");
5437
- this._overlay.classList.add("sidenav-overlay");
5438
- this._overlay.addEventListener("click", this.close);
5439
- document.body.appendChild(this._overlay);
5306
+ _beginClose() {
5307
+ this.isOpen = false;
5308
+ this._dialog?.classList.remove("dragging");
5309
+ this._clearShift();
5310
+ if (typeof this.options.onCloseStart === "function") {
5311
+ this.options.onCloseStart.call(this, this.el);
5312
+ }
5313
+ this._syncTriggers();
5314
+ }
5315
+ _finishClose() {
5316
+ if (typeof this.options.onCloseEnd === "function") {
5317
+ this.options.onCloseEnd.call(this, this.el);
5318
+ }
5319
+ }
5320
+ _setupDialog() {
5321
+ if (this.el instanceof HTMLDialogElement) {
5322
+ this._dialog = this.el;
5323
+ this._createdDialog = false;
5324
+ return;
5325
+ }
5326
+ const parent = this.el.parentElement;
5327
+ if (parent instanceof HTMLDialogElement && parent.classList.contains("sidenav-overlay")) {
5328
+ this._dialog = parent;
5329
+ this._createdDialog = false;
5330
+ return;
5331
+ }
5332
+ const dialog = document.createElement("dialog");
5333
+ dialog.classList.add("sidenav-overlay");
5334
+ this.el.replaceWith(dialog);
5335
+ dialog.appendChild(this.el);
5336
+ this._dialog = dialog;
5337
+ this._createdDialog = true;
5338
+ }
5339
+ _unwrapDialog() {
5340
+ if (!this._createdDialog || !this._dialog) return;
5341
+ this._dialog.replaceWith(this.el);
5342
+ this._dialog = null;
5343
+ this._createdDialog = false;
5344
+ }
5345
+ _createDragTarget() {
5346
+ if (!this.options.draggable) return;
5347
+ const dragTarget = document.createElement("div");
5348
+ dragTarget.classList.add("drag-target");
5349
+ dragTarget.style.width = this.options.dragTargetWidth;
5350
+ if (this.isFixed) dragTarget.dataset.fixed = "";
5351
+ document.body.appendChild(dragTarget);
5352
+ this.dragTarget = dragTarget;
5353
+ }
5354
+ _removeDragTarget() {
5355
+ this.dragTarget?.remove();
5356
+ this.dragTarget = null;
5357
+ }
5358
+ _setupClasses() {
5359
+ if (this.options.edge === "right") {
5360
+ this.el.classList.add("right-aligned");
5361
+ this._dialog?.classList.add("right-aligned");
5362
+ this.dragTarget?.classList.add("right-aligned");
5363
+ }
5440
5364
  }
5441
5365
  _setupEventHandlers() {
5442
5366
  if (_Sidenav._sidenavs.length === 0) {
5443
- document.body.addEventListener("click", this._handleTriggerClick);
5367
+ document.body.addEventListener("click", _Sidenav._handleTriggerClick);
5444
5368
  }
5445
5369
  const passive = { passive: true };
5446
- this.dragTarget.addEventListener("touchmove", this._handleDragTargetDrag, passive);
5447
- this.dragTarget.addEventListener("touchend", this._handleDragTargetRelease);
5448
- this._overlay.addEventListener("touchmove", this._handleCloseDrag, passive);
5449
- this._overlay.addEventListener("touchend", this._handleCloseRelease);
5450
- this.el.addEventListener("touchmove", this._handleCloseDrag, passive);
5451
- this.el.addEventListener("touchend", this._handleCloseRelease);
5370
+ this.dragTarget?.addEventListener("touchmove", this._handleDragTargetDrag, passive);
5371
+ this.dragTarget?.addEventListener("touchend", this._handleDragTargetRelease);
5372
+ this._dialog?.addEventListener("touchmove", this._handleCloseDrag, passive);
5373
+ this._dialog?.addEventListener("touchend", this._handleCloseRelease);
5374
+ this._dialog?.addEventListener("close", this._onDialogClose);
5452
5375
  this.el.addEventListener("click", this._handleCloseTriggerClick);
5453
- if (this.isFixed) {
5454
- window.addEventListener("resize", this._handleWindowResize, passive);
5455
- }
5456
- this._setAriaHidden();
5457
- this._setTabIndex();
5376
+ this._mql.addEventListener("change", this._onBreakpointChange);
5458
5377
  }
5459
5378
  _removeEventHandlers() {
5460
5379
  if (_Sidenav._sidenavs.length === 1) {
5461
- document.body.removeEventListener("click", this._handleTriggerClick);
5462
- }
5463
- this.dragTarget.removeEventListener("touchmove", this._handleDragTargetDrag);
5464
- this.dragTarget.removeEventListener("touchend", this._handleDragTargetRelease);
5465
- this._overlay.removeEventListener("touchmove", this._handleCloseDrag);
5466
- this._overlay.removeEventListener("touchend", this._handleCloseRelease);
5467
- this.el.removeEventListener("touchmove", this._handleCloseDrag);
5468
- this.el.removeEventListener("touchend", this._handleCloseRelease);
5469
- this.el.removeEventListener("click", this._handleCloseTriggerClick);
5470
- if (this.isFixed) {
5471
- window.removeEventListener("resize", this._handleWindowResize);
5380
+ document.body.removeEventListener("click", _Sidenav._handleTriggerClick);
5472
5381
  }
5382
+ this.dragTarget?.removeEventListener("touchmove", this._handleDragTargetDrag);
5383
+ this.dragTarget?.removeEventListener("touchend", this._handleDragTargetRelease);
5384
+ this._dialog?.removeEventListener("touchmove", this._handleCloseDrag);
5385
+ this._dialog?.removeEventListener("touchend", this._handleCloseRelease);
5386
+ this._dialog?.removeEventListener("close", this._onDialogClose);
5387
+ this.el.removeEventListener("click", this._handleCloseTriggerClick);
5388
+ this._mql.removeEventListener("change", this._onBreakpointChange);
5473
5389
  }
5474
- _handleTriggerClick(e) {
5475
- const trigger = e.target.closest(".sidenav-trigger");
5476
- if (e.target && trigger) {
5477
- const sidenavId = Utils.getIdFromTrigger(trigger);
5478
- const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5479
- if (sidenavInstance) {
5480
- sidenavInstance.open();
5481
- }
5390
+ static _handleTriggerClick(e) {
5391
+ const target = e.target;
5392
+ if (!(target instanceof Element)) return;
5393
+ const trigger = target.closest(".sidenav-trigger");
5394
+ if (!trigger || !(trigger instanceof HTMLElement)) return;
5395
+ const sidenavId = Utils.getIdFromTrigger(trigger);
5396
+ const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5397
+ if (sidenavInstance) {
5398
+ sidenavInstance.open();
5482
5399
  e.preventDefault();
5483
5400
  }
5484
5401
  }
5485
- // Set variables needed at the beginning of drag and stop any current transition.
5402
+ _isDraggable() {
5403
+ return this.options.draggable && !this._isCurrentlyFixed() && !this._verticallyScrolling;
5404
+ }
5405
+ _isCurrentlyFixed() {
5406
+ return this.isFixed && this._mql.matches;
5407
+ }
5486
5408
  _startDrag(e) {
5487
5409
  const clientX = e.targetTouches[0].clientX;
5488
5410
  this.isDragged = true;
5489
5411
  this._startingXpos = clientX;
5490
- this._xPos = this._startingXpos;
5491
- this._time = Date.now();
5492
- this._width = this.el.getBoundingClientRect().width;
5493
- this._overlay.style.display = "block";
5412
+ this._xPos = clientX;
5413
+ this._width = this._dialog?.getBoundingClientRect().width || this.el.getBoundingClientRect().width;
5494
5414
  this._initialScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5495
5415
  this._verticallyScrolling = false;
5416
+ this._dialog?.classList.add("dragging");
5417
+ if (this._dialog && !this._dialog.open) {
5418
+ try {
5419
+ this._dialog.showModal();
5420
+ } catch {
5421
+ }
5422
+ }
5496
5423
  }
5497
- //Set variables needed at each drag move update tick
5498
5424
  _dragMoveUpdate(e) {
5499
5425
  const clientX = e.targetTouches[0].clientX;
5500
5426
  const currentScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5501
- this.deltaX = Math.abs(this._xPos - clientX);
5502
5427
  this._xPos = clientX;
5503
- this.velocityX = this.deltaX / (Date.now() - this._time);
5504
- this._time = Date.now();
5505
5428
  if (this._initialScrollTop !== currentScrollTop) {
5506
5429
  this._verticallyScrolling = true;
5507
5430
  }
5508
5431
  }
5509
- _setupClasses() {
5510
- if (this.options.edge === "right") {
5511
- this.el.classList.add("right-aligned");
5512
- this.dragTarget.classList.add("right-aligned");
5513
- }
5514
- }
5515
- _removeClasses() {
5516
- this.el.classList.remove("right-aligned");
5517
- this.dragTarget.classList.remove("right-aligned");
5518
- }
5519
- _setupFixed() {
5520
- if (this._isCurrentlyFixed()) this.open();
5521
- }
5522
- _isDraggable() {
5523
- return this.options.draggable && !this._isCurrentlyFixed() && !this._verticallyScrolling;
5524
- }
5525
- _isCurrentlyFixed() {
5526
- return this.isFixed && window.innerWidth > 992;
5527
- }
5528
- _createDragTarget() {
5529
- const dragTarget = document.createElement("div");
5530
- dragTarget.classList.add("drag-target");
5531
- dragTarget.style.width = this.options.dragTargetWidth;
5532
- document.body.appendChild(dragTarget);
5533
- this.dragTarget = dragTarget;
5534
- }
5535
- _preventBodyScrolling() {
5536
- document.body.style.overflow = "hidden";
5537
- }
5538
- _enableBodyScrolling() {
5539
- document.body.style.overflow = "";
5540
- }
5541
- _animateIn() {
5542
- this._animateSidenavIn();
5543
- this._animateOverlayIn();
5544
- }
5545
- _animateOut() {
5546
- this._animateSidenavOut();
5547
- this._animateOverlayOut();
5548
- }
5549
- _animateSidenavIn() {
5550
- let slideOutPercent = this.options.edge === "left" ? -1 : 1;
5551
- if (this.isDragged) {
5552
- slideOutPercent = this.options.edge === "left" ? slideOutPercent + this.percentOpen : slideOutPercent - this.percentOpen;
5553
- }
5554
- const duration = this.options.inDuration;
5555
- this.el.style.transition = "none";
5556
- this.el.style.transform = "translateX(" + slideOutPercent * 100 + "%)";
5557
- setTimeout(() => {
5558
- this.el.style.transition = `transform ${duration}ms ease`;
5559
- this.el.style.transform = "translateX(0)";
5560
- }, 1);
5561
- setTimeout(() => {
5562
- if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
5563
- }, duration);
5564
- }
5565
- _animateSidenavOut() {
5566
- const endPercent = this.options.edge === "left" ? -1 : 1;
5567
- const duration = this.options.outDuration;
5568
- this.el.style.transition = `transform ${duration}ms ease`;
5569
- this.el.style.transform = "translateX(" + endPercent * 100 + "%)";
5570
- setTimeout(() => {
5571
- if (typeof this.options.onCloseEnd === "function")
5572
- this.options.onCloseEnd.call(this, this.el);
5573
- }, duration);
5574
- }
5575
- _animateOverlayIn() {
5576
- let start = 0;
5577
- if (this.isDragged) start = this.percentOpen;
5578
- else this._overlay.style.display = "block";
5579
- const duration = this.options.inDuration;
5580
- this._overlay.style.transition = "none";
5581
- this._overlay.style.opacity = start.toString();
5582
- setTimeout(() => {
5583
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5584
- this._overlay.style.opacity = "1";
5585
- }, 1);
5586
- }
5587
- _animateOverlayOut() {
5588
- const duration = this.options.outDuration;
5589
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5590
- this._overlay.style.opacity = "0";
5591
- setTimeout(() => {
5592
- this._overlay.style.display = "none";
5593
- }, duration);
5432
+ _rawDelta(e) {
5433
+ if (!this.isDragged) this._startDrag(e);
5434
+ this._dragMoveUpdate(e);
5435
+ return this._xPos - this._startingXpos;
5436
+ }
5437
+ _applyShift(shift, percentOpen) {
5438
+ this.percentOpen = percentOpen;
5439
+ const host = this._dialog ?? this.el;
5440
+ host.style.setProperty("--md-comp-nav-drawer-shift", `${shift}px`);
5441
+ host.style.setProperty("--md-comp-nav-drawer-open", String(percentOpen));
5442
+ }
5443
+ _clearShift() {
5444
+ const host = this._dialog ?? this.el;
5445
+ host.style.removeProperty("--md-comp-nav-drawer-shift");
5446
+ host.style.removeProperty("--md-comp-nav-drawer-open");
5447
+ }
5448
+ _syncTriggers() {
5449
+ if (!this.id) return;
5450
+ document.querySelectorAll(".sidenav-trigger").forEach((trigger) => {
5451
+ if (!(trigger instanceof HTMLElement)) return;
5452
+ if (Utils.getIdFromTrigger(trigger) !== this.id) return;
5453
+ trigger.setAttribute("aria-expanded", this.isOpen ? "true" : "false");
5454
+ trigger.setAttribute("aria-controls", this.id);
5455
+ });
5594
5456
  }
5595
5457
  };
5596
5458
  _Sidenav._sidenavs = [];
5597
5459
  var Sidenav = _Sidenav;
5598
5460
 
5599
5461
  // src/ts/components/slider.ts
5600
- var _defaults19 = {
5462
+ var _defaults18 = {
5601
5463
  indicators: true,
5602
5464
  height: 400,
5603
5465
  duration: 500,
@@ -5745,7 +5607,7 @@ var Slider = class _Slider extends Component {
5745
5607
  this.start();
5746
5608
  }
5747
5609
  static get defaults() {
5748
- return _defaults19;
5610
+ return _defaults18;
5749
5611
  }
5750
5612
  /**
5751
5613
  * Initializes instances of Slider.
@@ -5898,7 +5760,7 @@ var Slider = class _Slider extends Component {
5898
5760
  };
5899
5761
 
5900
5762
  // src/ts/components/tabs.ts
5901
- var _defaults20 = {
5763
+ var _defaults19 = {
5902
5764
  duration: 300,
5903
5765
  onShow: null,
5904
5766
  swipeable: false,
@@ -5976,7 +5838,7 @@ var Tabs = class _Tabs extends Component {
5976
5838
  this._setupEventHandlers();
5977
5839
  }
5978
5840
  static get defaults() {
5979
- return _defaults20;
5841
+ return _defaults19;
5980
5842
  }
5981
5843
  /**
5982
5844
  * Initializes instances of Tabs.
@@ -6015,7 +5877,7 @@ var Tabs = class _Tabs extends Component {
6015
5877
  }
6016
5878
  _queryTabLinks() {
6017
5879
  return this.el.querySelectorAll(
6018
- ":scope > a, :scope > .tab > a, :scope > li.tab > a"
5880
+ ":scope > a, :scope > .tab > a"
6019
5881
  );
6020
5882
  }
6021
5883
  _createIndicator() {
@@ -6057,7 +5919,7 @@ var Tabs = class _Tabs extends Component {
6057
5919
  }
6058
5920
  });
6059
5921
  const tabsWrapper = document.createElement("div");
6060
- tabsWrapper.classList.add("tabs-content", "carousel", "carousel-slider");
5922
+ tabsWrapper.classList.add("tabs-content", "carousel", "flat");
6061
5923
  tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]);
6062
5924
  tabsContent.forEach((tabContent) => {
6063
5925
  tabsWrapper.appendChild(tabContent);
@@ -6144,7 +6006,7 @@ var Tabs = class _Tabs extends Component {
6144
6006
  };
6145
6007
 
6146
6008
  // src/ts/components/tapTarget.ts
6147
- var _defaults21 = {
6009
+ var _defaults20 = {
6148
6010
  onOpen: null,
6149
6011
  onClose: null
6150
6012
  };
@@ -6259,7 +6121,7 @@ var _TapTarget = class _TapTarget extends Component {
6259
6121
  _TapTarget._taptargets.push(this);
6260
6122
  }
6261
6123
  static get defaults() {
6262
- return _defaults21;
6124
+ return _defaults20;
6263
6125
  }
6264
6126
  static init(els, options = {}) {
6265
6127
  return super.init(els, options, _TapTarget);
@@ -6332,7 +6194,7 @@ var _TapTarget = class _TapTarget extends Component {
6332
6194
  _setupEventHandlers() {
6333
6195
  if (!this.originEl) return;
6334
6196
  this.originEl.addEventListener("click", this._handleTargetToggle);
6335
- if (!this.originEl.matches('button, a, [tabindex], .btn, [role="button"]')) {
6197
+ if (!this.originEl.matches('button, a, [tabindex], [role="button"]')) {
6336
6198
  this.originEl.tabIndex = 0;
6337
6199
  this.originEl.addEventListener("keydown", this._handleOriginKeydown);
6338
6200
  }
@@ -6365,7 +6227,7 @@ _TapTarget._taptargets = [];
6365
6227
  var TapTarget = _TapTarget;
6366
6228
 
6367
6229
  // src/ts/components/timepicker.ts
6368
- var _defaults22 = {
6230
+ var _defaults21 = {
6369
6231
  dialRadius: 135,
6370
6232
  outerRadius: 105,
6371
6233
  innerRadius: 70,
@@ -6563,7 +6425,7 @@ var _Timepicker = class _Timepicker extends Component {
6563
6425
  }
6564
6426
  }
6565
6427
  static get defaults() {
6566
- return _defaults22;
6428
+ return _defaults21;
6567
6429
  }
6568
6430
  /**
6569
6431
  * Initializes instances of Timepicker.
@@ -6646,7 +6508,7 @@ var _Timepicker = class _Timepicker extends Component {
6646
6508
  }
6647
6509
  /*private _createButton(text: string, visibility: string): HTMLButtonElement {
6648
6510
  const button = document.createElement('button');
6649
- button.classList.add('btn', 'waves-effect', 'text');
6511
+ button.classList.add('waves-effect', 'text');
6650
6512
  button.style.visibility = visibility;
6651
6513
  button.type = 'button';
6652
6514
  button.tabIndex = -1;
@@ -6687,14 +6549,14 @@ var _Timepicker = class _Timepicker extends Component {
6687
6549
  _clockSetup() {
6688
6550
  if (this.options.twelveHour) {
6689
6551
  this._amBtn = document.createElement("div");
6690
- this._amBtn.classList.add("am-btn", "btn");
6552
+ this._amBtn.classList.add("am-btn");
6691
6553
  this._amBtn.innerText = "AM";
6692
6554
  this._amBtn.tabIndex = 0;
6693
6555
  this._amBtn.addEventListener("click", this._handleAmPmClick);
6694
6556
  this._amBtn.addEventListener("keypress", this._handleAmPmKeypress);
6695
6557
  this.spanAmPm.appendChild(this._amBtn);
6696
6558
  this._pmBtn = document.createElement("div");
6697
- this._pmBtn.classList.add("pm-btn", "btn");
6559
+ this._pmBtn.classList.add("pm-btn");
6698
6560
  this._pmBtn.innerText = "PM";
6699
6561
  this._pmBtn.tabIndex = 0;
6700
6562
  this._pmBtn.addEventListener("click", this._handleAmPmClick);
@@ -6901,19 +6763,6 @@ var _Timepicker = class _Timepicker extends Component {
6901
6763
  this.hours = (/* @__PURE__ */ new Date()).getHours();
6902
6764
  this.inputHours.value = (this.hours % (this.options.twelveHour ? 12 : 24)).toString();
6903
6765
  }
6904
- // deprecated
6905
- open() {
6906
- console.warn(
6907
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6908
- );
6909
- return this;
6910
- }
6911
- close() {
6912
- console.warn(
6913
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6914
- );
6915
- return this;
6916
- }
6917
6766
  };
6918
6767
  _Timepicker._template = `<div class="timepicker-container">
6919
6768
  <div class="timepicker-digital-display">
@@ -6946,7 +6795,7 @@ _Timepicker._template = `<div class="timepicker-container">
6946
6795
  var Timepicker = _Timepicker;
6947
6796
 
6948
6797
  // src/ts/components/toasts.ts
6949
- var _defaults23 = {
6798
+ var _defaults22 = {
6950
6799
  text: "",
6951
6800
  action: "",
6952
6801
  onAction: null,
@@ -6978,7 +6827,7 @@ var _Toast = class _Toast {
6978
6827
  this._setTimer();
6979
6828
  }
6980
6829
  static get defaults() {
6981
- return _defaults23;
6830
+ return _defaults22;
6982
6831
  }
6983
6832
  static getInstance(el) {
6984
6833
  return el["Expressive_Toast"];
@@ -7003,8 +6852,8 @@ var _Toast = class _Toast {
7003
6852
  }
7004
6853
  static _onDragStart(e) {
7005
6854
  const target = e.target;
7006
- if (target && !target.closest("button, a") && target.closest(".toast, .snackbar")) {
7007
- const toastElem = target.closest(".toast, .snackbar");
6855
+ if (target && !target.closest("button, a") && target.closest(".snackbar")) {
6856
+ const toastElem = target.closest(".snackbar");
7008
6857
  const toast = toastElem["Expressive_Toast"];
7009
6858
  if (!toast) return;
7010
6859
  toast.panning = true;
@@ -7071,7 +6920,7 @@ var _Toast = class _Toast {
7071
6920
  const node = toast.content.cloneNode(true);
7072
6921
  toast = node.firstElementChild;
7073
6922
  }
7074
- toast.classList.add("toast", "snackbar");
6923
+ toast.classList.add("snackbar");
7075
6924
  toast.setAttribute("role", "status");
7076
6925
  toast.setAttribute("aria-live", "polite");
7077
6926
  toast.setAttribute("aria-atomic", "true");
@@ -7191,7 +7040,7 @@ _Toast._draggedToast = null;
7191
7040
  var Toast = _Toast;
7192
7041
 
7193
7042
  // src/ts/components/tooltip.ts
7194
- var _defaults24 = {
7043
+ var _defaults23 = {
7195
7044
  exitDelay: 200,
7196
7045
  enterDelay: 0,
7197
7046
  text: "",
@@ -7259,7 +7108,7 @@ var Tooltip = class _Tooltip extends Component {
7259
7108
  this._setupEventHandlers();
7260
7109
  }
7261
7110
  static get defaults() {
7262
- return _defaults24;
7111
+ return _defaults23;
7263
7112
  }
7264
7113
  /**
7265
7114
  * Initializes instances of Tooltip.
@@ -7282,7 +7131,7 @@ var Tooltip = class _Tooltip extends Component {
7282
7131
  }
7283
7132
  _appendTooltipEl() {
7284
7133
  this.tooltipEl = document.createElement("div");
7285
- this.tooltipEl.classList.add("tooltip", "material-tooltip");
7134
+ this.tooltipEl.classList.add("tooltip");
7286
7135
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
7287
7136
  this.tooltipEl.setAttribute("role", "tooltip");
7288
7137
  this.el.setAttribute("aria-describedby", this.tooltipEl.id);
@@ -7443,7 +7292,6 @@ var AUTO_INIT_COMPONENTS = {
7443
7292
  Datepicker: { component: Datepicker, selector: ".datepicker" },
7444
7293
  Dropdown: { component: Dropdown, selector: ".dropdown-trigger" },
7445
7294
  Lightbox: { component: Lightbox, selector: ".lightboxed" },
7446
- Modal: { component: Modal, selector: ".modal" },
7447
7295
  Parallax: { component: Parallax, selector: ".parallax" },
7448
7296
  Pushpin: { component: Pushpin, selector: ".pushpin" },
7449
7297
  ScrollSpy: { component: ScrollSpy, selector: ".scrollspy" },
@@ -7467,7 +7315,7 @@ function AutoInit(context = document.body, options) {
7467
7315
  }
7468
7316
 
7469
7317
  // src/ts/index.ts
7470
- var version = "0.3.0";
7318
+ var version = "0.4.0";
7471
7319
  if (typeof document !== "undefined") {
7472
7320
  document.addEventListener("keydown", Utils.docHandleKeydown, true);
7473
7321
  document.addEventListener("keyup", Utils.docHandleKeyup, true);