@expressivecss/expressive 0.2.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 (80) hide show
  1. package/README.md +8 -8
  2. package/dist/css/expressive.css +1915 -1566
  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 +1338 -1528
  7. package/dist/js/expressive.cjs.map +4 -4
  8. package/dist/js/expressive.js +1338 -1528
  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 +1338 -1529
  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 +19 -43
  16. package/dist/types/components/cards.d.ts +3 -6
  17. package/dist/types/components/carousel.d.ts +42 -48
  18. package/dist/types/components/characterCounter.d.ts +3 -5
  19. package/dist/types/components/chips.d.ts +4 -4
  20. package/dist/types/components/collapsible.d.ts +28 -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 +7 -37
  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 +25 -26
  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 +3 -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 +6 -5
  45. package/src/sass/components/_breadcrumb.scss +93 -16
  46. package/src/sass/components/_buttons.scss +212 -145
  47. package/src/sass/components/_cards.scss +50 -123
  48. package/src/sass/components/_carousel.scss +128 -63
  49. package/src/sass/components/_chips.scss +1 -1
  50. package/src/sass/components/_collapsible.scss +158 -60
  51. package/src/sass/components/_collection.scss +146 -80
  52. package/src/sass/components/_datepicker.scss +1 -15
  53. package/src/sass/components/_dropdown.scss +110 -14
  54. package/src/sass/components/_icons-material-design.scss +77 -4
  55. package/src/sass/components/_index.scss +1 -0
  56. package/src/sass/components/_lightbox.scss +4 -0
  57. package/src/sass/components/_modal.scss +13 -31
  58. package/src/sass/components/_navbar.scss +24 -6
  59. package/src/sass/components/_page-footer.scss +134 -15
  60. package/src/sass/components/_pagination.scss +131 -25
  61. package/src/sass/components/_parallax.scss +96 -21
  62. package/src/sass/components/_preloader.scss +145 -300
  63. package/src/sass/components/_scrollspy.scss +18 -0
  64. package/src/sass/components/_sidenav.scss +230 -119
  65. package/src/sass/components/_slider.scss +8 -0
  66. package/src/sass/components/_table_of_contents.scss +30 -14
  67. package/src/sass/components/_tabs.scss +54 -35
  68. package/src/sass/components/_tapTarget.scss +128 -45
  69. package/src/sass/components/_toast.scss +10 -11
  70. package/src/sass/components/_toolbar.scss +2 -2
  71. package/src/sass/components/_tooltip.scss +4 -9
  72. package/src/sass/components/_transitions.scss +0 -5
  73. package/src/sass/components/forms/_index.scss +0 -5
  74. package/src/sass/components/forms/_input-fields.scss +49 -52
  75. package/src/sass/components/forms/_select.scss +175 -60
  76. package/src/sass/components/forms/_switches.scss +21 -8
  77. package/src/sass/utilities/_helpers.scss +1 -3
  78. package/src/sass/utilities/_typescale.scss +0 -5
  79. package/src/sass/utilities/_visibility.scss +2 -2
  80. 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.
@@ -1476,7 +1550,7 @@ var _defaults4 = {
1476
1550
  data: [],
1477
1551
  placeholder: "",
1478
1552
  secondaryPlaceholder: "",
1479
- closeIconClass: "material-icons",
1553
+ closeIconClass: "material-symbols",
1480
1554
  autocompleteOptions: {},
1481
1555
  autocompleteOnly: false,
1482
1556
  limit: Infinity,
@@ -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);
@@ -2115,83 +2189,76 @@ var _defaults6 = {
2115
2189
  var FloatingActionButton = class _FloatingActionButton extends Component {
2116
2190
  constructor(el, options) {
2117
2191
  super(el, options, _FloatingActionButton);
2118
- /** Toolbar-mode backdrop, kept so closing can take it back out. */
2119
- this._backdrop = null;
2120
- this._handleFABClick = () => {
2121
- this._handleFABToggle();
2122
- };
2123
- this._handleFABKeyPress = (e) => {
2124
- if (Utils.keys.ENTER.includes(e.key)) {
2125
- this._handleFABToggle();
2126
- }
2127
- };
2128
- this._handleFABToggle = () => {
2129
- if (this.isOpen) {
2130
- this.close();
2131
- } else {
2132
- this.open();
2133
- }
2134
- };
2135
- this._handleDocumentClick = (e) => {
2136
- const elem = e.target;
2137
- if (elem !== this._menu) this.close();
2138
- };
2139
2192
  /**
2140
2193
  * Open FAB.
2141
2194
  */
2142
2195
  this.open = () => {
2143
2196
  if (this.isOpen) return;
2144
- if (this.options.toolbarEnabled) this._animateInToolbar();
2145
- else this._animateInFAB();
2146
2197
  this.isOpen = true;
2198
+ this.el.classList.add("active");
2199
+ this._anchor?.setAttribute("aria-expanded", "true");
2200
+ document.addEventListener("click", this._handleDocumentClick);
2201
+ document.addEventListener("keydown", this._handleDocumentKeydown);
2147
2202
  };
2148
2203
  /**
2149
2204
  * Close FAB.
2150
2205
  */
2151
2206
  this.close = () => {
2152
2207
  if (!this.isOpen) return;
2153
- if (this.options.toolbarEnabled) {
2154
- window.removeEventListener("scroll", this.close, true);
2155
- document.body.removeEventListener("click", this._handleDocumentClick, true);
2156
- this._animateOutToolbar();
2157
- } else {
2158
- this._animateOutFAB();
2159
- }
2160
2208
  this.isOpen = false;
2209
+ this.el.classList.remove("active");
2210
+ this._anchor?.setAttribute("aria-expanded", "false");
2211
+ document.removeEventListener("click", this._handleDocumentClick);
2212
+ document.removeEventListener("keydown", this._handleDocumentKeydown);
2213
+ };
2214
+ this._handleFABClick = (e) => {
2215
+ e.stopPropagation();
2216
+ this._toggle();
2217
+ };
2218
+ this._handleAnchorKeydown = (e) => {
2219
+ if (Utils.keys.ENTER.includes(e.key) || e.key === " ") {
2220
+ e.preventDefault();
2221
+ this._toggle();
2222
+ }
2223
+ };
2224
+ this._handleDocumentKeydown = (e) => {
2225
+ if (Utils.keys.ESC.includes(e.key)) this.close();
2226
+ };
2227
+ this._handleDocumentClick = (e) => {
2228
+ const target = e.target;
2229
+ if (!(target instanceof Node) || this.el.contains(target)) return;
2230
+ this.close();
2161
2231
  };
2162
2232
  this.el["Expressive_FloatingActionButton"] = this;
2233
+ const fromMarkup = this._directionFromClass();
2234
+ const toolbar = el.classList.contains("toolbar") || options.toolbarEnabled === true;
2235
+ const clickToToggle = el.classList.contains("click-to-toggle") || options.hoverEnabled === false;
2163
2236
  this.options = {
2164
2237
  ..._FloatingActionButton.defaults,
2165
- ...options
2238
+ ...options,
2239
+ direction: options.direction ?? fromMarkup ?? _FloatingActionButton.defaults.direction,
2240
+ hoverEnabled: !clickToToggle,
2241
+ toolbarEnabled: toolbar
2166
2242
  };
2167
2243
  this.isOpen = false;
2168
- this._anchor = this.el.querySelector("a, button");
2169
- this._menu = this.el.querySelector("ul");
2170
- this._floatingBtns = Array.from(this.el.querySelectorAll("ul .btn-floating"));
2171
- this._floatingBtnsReverse = this._floatingBtns.reverse();
2172
- this.offsetY = 0;
2173
- this.offsetX = 0;
2244
+ this._anchor = this.el.querySelector(":scope > a, :scope > button");
2245
+ this._menu = this.el.querySelector("ul, menu");
2174
2246
  this.el.classList.add(`direction-${this.options.direction}`);
2175
- if (this._anchor) this._anchor.tabIndex = 0;
2176
- if (this._menu) this._menu.ariaExpanded = "false";
2177
- if (this.options.direction === "top")
2178
- this.offsetY = 40;
2179
- else if (this.options.direction === "right")
2180
- this.offsetX = -40;
2181
- else if (this.options.direction === "bottom")
2182
- this.offsetY = -40;
2183
- else
2184
- this.offsetX = 40;
2247
+ if (clickToToggle) this.el.classList.add("click-to-toggle");
2248
+ if (toolbar) this.el.classList.add("toolbar");
2249
+ if (this._anchor) {
2250
+ this._anchor.setAttribute("aria-haspopup", "menu");
2251
+ this._anchor.setAttribute("aria-expanded", "false");
2252
+ if (this._anchor instanceof HTMLAnchorElement && !this._anchor.hasAttribute("href") && this._anchor.tabIndex < 0) {
2253
+ this._anchor.tabIndex = 0;
2254
+ }
2255
+ }
2256
+ if (this._menu) this._menu.setAttribute("role", "menu");
2185
2257
  this._setupEventHandlers();
2186
2258
  }
2187
2259
  static get defaults() {
2188
2260
  return _defaults6;
2189
2261
  }
2190
- /**
2191
- * Initializes instances of FloatingActionButton.
2192
- * @param els HTML elements.
2193
- * @param options Component options.
2194
- */
2195
2262
  static init(els, options = {}) {
2196
2263
  return super.init(els, options, _FloatingActionButton);
2197
2264
  }
@@ -2199,229 +2266,109 @@ var FloatingActionButton = class _FloatingActionButton extends Component {
2199
2266
  return el["Expressive_FloatingActionButton"];
2200
2267
  }
2201
2268
  destroy() {
2202
- this._removeEventHandlers();
2203
2269
  this.close();
2270
+ this._removeEventHandlers();
2204
2271
  this.el["Expressive_FloatingActionButton"] = void 0;
2205
2272
  }
2273
+ _directionFromClass() {
2274
+ const match = [...this.el.classList].find((c) => c.startsWith("direction-"));
2275
+ const value = match?.slice("direction-".length);
2276
+ if (value === "top" || value === "right" || value === "bottom" || value === "left") {
2277
+ return value;
2278
+ }
2279
+ return null;
2280
+ }
2206
2281
  _setupEventHandlers() {
2207
- if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
2208
- this.el.addEventListener("mouseenter", this.open);
2209
- this.el.addEventListener("mouseleave", this.close);
2210
- } else {
2211
- this.el.addEventListener("click", this._handleFABClick);
2282
+ this.el.addEventListener("click", this._handleFABClick);
2283
+ if (this._anchor instanceof HTMLAnchorElement && !this._anchor.hasAttribute("href")) {
2284
+ this._anchor.addEventListener("keydown", this._handleAnchorKeydown);
2212
2285
  }
2213
- this.el.addEventListener("keypress", this._handleFABKeyPress);
2214
2286
  }
2215
2287
  _removeEventHandlers() {
2216
- if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
2217
- this.el.removeEventListener("mouseenter", this.open);
2218
- this.el.removeEventListener("mouseleave", this.close);
2219
- } else {
2220
- this.el.removeEventListener("click", this._handleFABClick);
2221
- }
2222
- this.el.removeEventListener("keypress", this._handleFABKeyPress);
2223
- }
2224
- _animateInFAB() {
2225
- this.el.classList.add("active");
2226
- if (this._menu) this._menu.ariaExpanded = "true";
2227
- const delayIncrement = 40;
2228
- const duration = 275;
2229
- this._floatingBtnsReverse.forEach((el, index) => {
2230
- const delay = delayIncrement * index;
2231
- el.style.transition = "none";
2232
- el.style.opacity = "0";
2233
- el.style.transform = `translate(${this.offsetX}px, ${this.offsetY}px) scale(0.4)`;
2234
- setTimeout(() => {
2235
- el.style.opacity = "0.4";
2236
- setTimeout(() => {
2237
- el.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
2238
- el.style.opacity = "1";
2239
- el.style.transform = "translate(0, 0) scale(1)";
2240
- el.tabIndex = 0;
2241
- }, 1);
2242
- }, delay);
2243
- });
2244
- }
2245
- _animateOutFAB() {
2246
- const duration = 175;
2247
- setTimeout(() => {
2248
- this.el.classList.remove("active");
2249
- if (this._menu) this._menu.ariaExpanded = "false";
2250
- }, duration);
2251
- this._floatingBtnsReverse.forEach((el) => {
2252
- el.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
2253
- el.style.opacity = "0";
2254
- el.style.transform = `translate(${this.offsetX}px, ${this.offsetY}px) scale(0.4)`;
2255
- el.tabIndex = -1;
2256
- });
2257
- }
2258
- _animateInToolbar() {
2259
- const windowWidth = window.innerWidth;
2260
- const windowHeight = window.innerHeight;
2261
- const btnRect = this.el.getBoundingClientRect();
2262
- const fabColor = getComputedStyle(this._anchor).backgroundColor;
2263
- const backdrop = document.createElement("div");
2264
- backdrop.classList.add("fab-backdrop");
2265
- backdrop.style.backgroundColor = fabColor;
2266
- this._anchor.append(backdrop);
2267
- this._backdrop = backdrop;
2268
- const backdropWidth = backdrop.clientWidth;
2269
- const scaleFactor = backdropWidth > 0 ? windowWidth / backdropWidth : 1;
2270
- this.offsetX = btnRect.left - windowWidth / 2 + btnRect.width / 2;
2271
- this.offsetY = windowHeight - btnRect.bottom;
2272
- this.btnBottom = btnRect.bottom;
2273
- this.btnLeft = btnRect.left;
2274
- this.btnWidth = btnRect.width;
2275
- this.el.classList.add("active");
2276
- this.el.style.textAlign = "center";
2277
- this.el.style.width = "100%";
2278
- this.el.style.bottom = "0";
2279
- this.el.style.left = "0";
2280
- this.el.style.transform = "translateX(" + this.offsetX + "px)";
2281
- this.el.style.transition = "none";
2282
- if (this._menu) this._menu.ariaExpanded = "true";
2283
- this._anchor.style.transform = `translateY(${this.offsetY}px)`;
2284
- this._anchor.style.transition = "none";
2285
- setTimeout(() => {
2286
- this.el.style.transform = "";
2287
- this.el.style.transition = "transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s";
2288
- this._anchor.style.overflow = "visible";
2289
- this._anchor.style.transform = "";
2290
- this._anchor.style.transition = "transform .2s";
2291
- setTimeout(() => {
2292
- this.el.style.overflow = "hidden";
2293
- this.el.style.backgroundColor = fabColor;
2294
- backdrop.style.transform = "scale(" + scaleFactor + ")";
2295
- backdrop.style.transition = "transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)";
2296
- this._menu.querySelectorAll("li > a").forEach((a) => {
2297
- a.style.opacity = "1";
2298
- a.tabIndex = 0;
2299
- });
2300
- window.addEventListener("scroll", this.close, true);
2301
- document.body.addEventListener("click", this._handleDocumentClick, true);
2302
- }, 100);
2303
- }, 0);
2288
+ this.el.removeEventListener("click", this._handleFABClick);
2289
+ this._anchor?.removeEventListener("keydown", this._handleAnchorKeydown);
2304
2290
  }
2305
- /**
2306
- * Reverse {@link _animateInToolbar}.
2307
- *
2308
- * Closing used to only unbind the listeners, leaving the FAB stretched
2309
- * across the viewport with its backdrop still in the DOM - and a fresh
2310
- * backdrop appended on every subsequent open.
2311
- */
2312
- _animateOutToolbar() {
2313
- const backdrop = this._backdrop;
2314
- this._backdrop = null;
2315
- this._menu?.querySelectorAll("li > a").forEach((a) => {
2316
- a.style.opacity = "";
2317
- a.tabIndex = -1;
2318
- });
2319
- if (backdrop) {
2320
- backdrop.style.transition = "transform .2s";
2321
- backdrop.style.transform = "scale(0)";
2322
- }
2323
- this.el.style.overflow = "";
2324
- this.el.style.backgroundColor = "";
2325
- this.el.style.transition = "transform .2s";
2326
- this.el.style.transform = `translateX(${this.offsetX}px)`;
2327
- this._anchor.style.transition = "transform .2s";
2328
- this._anchor.style.transform = `translateY(${this.offsetY}px)`;
2329
- setTimeout(() => {
2330
- backdrop?.remove();
2331
- this.el.classList.remove("active");
2332
- if (this._menu) this._menu.ariaExpanded = "false";
2333
- this.el.style.textAlign = "";
2334
- this.el.style.width = "";
2335
- this.el.style.bottom = "";
2336
- this.el.style.left = "";
2337
- this.el.style.transform = "";
2338
- this.el.style.transition = "";
2339
- this._anchor.style.overflow = "";
2340
- this._anchor.style.transform = "";
2341
- this._anchor.style.transition = "";
2342
- }, 200);
2291
+ _toggle() {
2292
+ if (this.isOpen) this.close();
2293
+ else this.open();
2343
2294
  }
2344
2295
  };
2345
2296
 
2346
2297
  // src/ts/components/carousel.ts
2347
2298
  var _defaults7 = {
2348
2299
  duration: 200,
2349
- // ms
2350
2300
  dist: -100,
2351
- // zoom scale TODO: make this more intuitive as an option
2352
2301
  shift: 0,
2353
- // spacing for center image
2354
2302
  padding: 0,
2355
- // Padding between non center items
2356
2303
  numVisible: 5,
2357
- // Number of visible items in carousel
2358
2304
  fullWidth: false,
2359
- // Change to full width styles
2360
2305
  indicators: false,
2361
- // Toggle indicators
2362
2306
  noWrap: false,
2363
- // Don't wrap around and cycle through items.
2364
2307
  onCycleTo: null
2365
- // Callback for when a new slide is cycled to.
2366
2308
  };
2367
- var Carousel = class _Carousel extends Component {
2309
+ var _Carousel = class _Carousel extends Component {
2368
2310
  constructor(el, options) {
2369
2311
  super(el, options, _Carousel);
2370
- /** The index of the center carousel item. */
2371
2312
  this.center = 0;
2372
- // Built once per instance. Creating the throttled function inside the
2373
- // handler - as this used to - produced a fresh closure per resize event and
2374
- // never actually called it, so resizing did nothing at all.
2313
+ this._ownIndicators = false;
2314
+ this._trackEl = null;
2315
+ this._ignoreScroll = false;
2316
+ this._trackRaf = null;
2317
+ this._started = false;
2375
2318
  this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
2376
2319
  this._handleCarouselTap = (e) => {
2377
- if (e.type === "mousedown" && e.target.tagName === "IMG") {
2320
+ if (e.pointerType === "mouse" && e.button !== 0) return;
2321
+ if (e.target instanceof HTMLElement && e.target.tagName === "IMG") {
2378
2322
  e.preventDefault();
2379
2323
  }
2380
2324
  this.pressed = true;
2381
2325
  this.dragged = false;
2382
2326
  this.verticalDragged = false;
2383
- this.reference = this._xpos(e);
2384
- this.referenceY = this._ypos(e);
2327
+ this.reference = e.clientX;
2328
+ this.referenceY = e.clientY;
2385
2329
  this.velocity = this.amplitude = 0;
2386
2330
  this.frame = this.offset;
2387
2331
  this.timestamp = Date.now();
2388
- clearInterval(this.ticker);
2389
- this.ticker = setInterval(this._track, 100);
2332
+ try {
2333
+ this.el.setPointerCapture(e.pointerId);
2334
+ } catch {
2335
+ }
2336
+ if (this._trackRaf !== null) cancelAnimationFrame(this._trackRaf);
2337
+ const loop = () => {
2338
+ this._track();
2339
+ if (this.pressed) this._trackRaf = requestAnimationFrame(loop);
2340
+ else this._trackRaf = null;
2341
+ };
2342
+ this._trackRaf = requestAnimationFrame(loop);
2390
2343
  };
2391
2344
  this._handleCarouselDrag = (e) => {
2392
- let x, y, delta, deltaY;
2393
- if (this.pressed) {
2394
- x = this._xpos(e);
2395
- y = this._ypos(e);
2396
- delta = this.reference - x;
2397
- deltaY = Math.abs(this.referenceY - y);
2398
- if (deltaY < 30 && !this.verticalDragged) {
2399
- if (delta > 2 || delta < -2) {
2400
- this.dragged = true;
2401
- this.reference = x;
2402
- this._scroll(this.offset + delta);
2403
- }
2404
- } else if (this.dragged) {
2405
- e.preventDefault();
2406
- e.stopPropagation();
2407
- return false;
2408
- } else {
2409
- this.verticalDragged = true;
2345
+ if (!this.pressed) return;
2346
+ const delta = this.reference - e.clientX;
2347
+ const deltaY = Math.abs(this.referenceY - e.clientY);
2348
+ if (deltaY < 30 && !this.verticalDragged) {
2349
+ if (delta > 2 || delta < -2) {
2350
+ this.dragged = true;
2351
+ this.reference = e.clientX;
2352
+ this._scroll(this.offset + delta);
2410
2353
  }
2411
- }
2412
- if (this.dragged) {
2354
+ } else if (this.dragged) {
2413
2355
  e.preventDefault();
2414
- e.stopPropagation();
2415
- return false;
2356
+ } else {
2357
+ this.verticalDragged = true;
2416
2358
  }
2359
+ if (this.dragged) e.preventDefault();
2417
2360
  };
2418
2361
  this._handleCarouselRelease = (e) => {
2419
- if (this.pressed) {
2420
- this.pressed = false;
2421
- } else {
2422
- return;
2362
+ if (!this.pressed) return;
2363
+ this.pressed = false;
2364
+ if (this._trackRaf !== null) {
2365
+ cancelAnimationFrame(this._trackRaf);
2366
+ this._trackRaf = null;
2367
+ }
2368
+ try {
2369
+ this.el.releasePointerCapture(e.pointerId);
2370
+ } catch {
2423
2371
  }
2424
- clearInterval(this.ticker);
2425
2372
  this.target = this.offset;
2426
2373
  if (this.velocity > 10 || this.velocity < -10) {
2427
2374
  this.amplitude = 0.9 * this.velocity;
@@ -2438,86 +2385,91 @@ var Carousel = class _Carousel extends Component {
2438
2385
  this.amplitude = this.target - this.offset;
2439
2386
  this.timestamp = Date.now();
2440
2387
  requestAnimationFrame(this._autoScroll);
2388
+ if (this.dragged) e.preventDefault();
2389
+ };
2390
+ this._handleCarouselClick = (e) => {
2441
2391
  if (this.dragged) {
2442
2392
  e.preventDefault();
2443
2393
  e.stopPropagation();
2394
+ return;
2444
2395
  }
2445
- return false;
2446
- };
2447
- this._handleCarouselClick = (e) => {
2448
- if (this.dragged) {
2396
+ const clickedElem = e.target.closest(".carousel-item");
2397
+ if (!clickedElem || !this.el.contains(clickedElem)) return;
2398
+ const clickedIndex = this.images.indexOf(clickedElem);
2399
+ const diff = this._wrap(this.center) - clickedIndex;
2400
+ if (diff !== 0) {
2449
2401
  e.preventDefault();
2450
2402
  e.stopPropagation();
2451
- return false;
2452
- } else if (!this.options.fullWidth) {
2453
- const clickedElem = e.target.closest(".carousel-item");
2454
- if (!clickedElem) return;
2455
- const clickedIndex = [...clickedElem.parentNode.children].indexOf(clickedElem);
2456
- const diff = this._wrap(this.center) - clickedIndex;
2457
- if (diff !== 0) {
2458
- e.preventDefault();
2459
- e.stopPropagation();
2460
- }
2461
- if (clickedIndex < 0) {
2462
- if (e.clientX - e.target.getBoundingClientRect().left > this.el.clientWidth / 2) {
2463
- this.next();
2464
- } else {
2465
- this.prev();
2466
- }
2403
+ }
2404
+ if (clickedIndex < 0) {
2405
+ if (e.clientX - e.target.getBoundingClientRect().left > this.el.clientWidth / 2) {
2406
+ this.next();
2467
2407
  } else {
2468
- this._cycleTo(clickedIndex);
2408
+ this.prev();
2469
2409
  }
2410
+ } else {
2411
+ this._cycleTo(clickedIndex);
2470
2412
  }
2471
2413
  };
2472
2414
  this._handleIndicatorClick = (e) => {
2473
2415
  e.stopPropagation();
2474
- this._handleIndicatorInteraction(e);
2416
+ const indicator = e.target.closest(".indicator-item");
2417
+ if (!indicator || !this._indicators.contains(indicator)) return;
2418
+ const index = [...this._indicators.children].indexOf(indicator);
2419
+ if (index < 0) return;
2420
+ this._cycleTo(index);
2475
2421
  };
2476
- this._handleIndicatorKeyPress = (e) => {
2477
- e.stopPropagation();
2478
- if (Utils.keys.ENTER.includes(e.key)) {
2479
- this._handleIndicatorInteraction(e);
2422
+ this._handleKeydown = (e) => {
2423
+ const target = e.target;
2424
+ if (target.closest('input, textarea, select, [contenteditable="true"]')) return;
2425
+ if (Utils.keys.ARROW_RIGHT.includes(e.key)) {
2426
+ e.preventDefault();
2427
+ this.next();
2428
+ } else if (Utils.keys.ARROW_LEFT.includes(e.key)) {
2429
+ e.preventDefault();
2430
+ this.prev();
2480
2431
  }
2481
2432
  };
2482
- this._handleIndicatorInteraction = (e) => {
2483
- const indicator = e.target.closest(".indicator-item");
2484
- if (indicator) {
2485
- const index = [...indicator.parentNode.children].indexOf(indicator);
2486
- this._cycleTo(index);
2487
- }
2433
+ this._handleFlatScroll = () => {
2434
+ if (this._ignoreScroll) return;
2435
+ const index = this._nearestIndex();
2436
+ if (index !== this.center) this._syncActive(index, this.dragged);
2488
2437
  };
2489
2438
  this._handleResize = () => {
2439
+ if (!this.images.length) return;
2440
+ if (this._flat) {
2441
+ this._scrollToIndex(this.center, false);
2442
+ return;
2443
+ }
2490
2444
  if (this.options.fullWidth) {
2491
- const firstItem = this.el.querySelector(".carousel-item");
2492
- const activeItem = this.el.querySelector(".carousel-item.active");
2493
- if (!firstItem || !activeItem) return;
2445
+ const firstItem = this.images[0];
2446
+ if (!firstItem) return;
2494
2447
  this.itemWidth = firstItem.clientWidth;
2495
- this.imageHeight = activeItem.clientHeight;
2496
2448
  this.dim = this.itemWidth * 2 + this.options.padding;
2497
2449
  this.offset = this.center * 2 * this.itemWidth;
2498
2450
  this.target = this.offset;
2499
- this._setCarouselHeight(true);
2500
2451
  } else {
2501
2452
  this._scroll();
2502
2453
  }
2503
2454
  };
2504
2455
  this._track = () => {
2505
- const now = Date.now(), elapsed = now - this.timestamp, delta = this.offset - this.frame, v = 1e3 * delta / (1 + elapsed);
2456
+ const now = Date.now();
2457
+ const elapsed = now - this.timestamp;
2458
+ const delta = this.offset - this.frame;
2459
+ const v = 1e3 * delta / (1 + elapsed);
2506
2460
  this.timestamp = now;
2507
2461
  this.frame = this.offset;
2508
2462
  this.velocity = 0.8 * v + 0.2 * this.velocity;
2509
2463
  };
2510
2464
  this._autoScroll = () => {
2511
- let elapsed, delta;
2512
- if (this.amplitude) {
2513
- elapsed = Date.now() - this.timestamp;
2514
- delta = this.amplitude * Math.exp(-elapsed / this.options.duration);
2515
- if (delta > 2 || delta < -2) {
2516
- this._scroll(this.target - delta);
2517
- requestAnimationFrame(this._autoScroll);
2518
- } else {
2519
- this._scroll(this.target);
2520
- }
2465
+ if (!this.amplitude) return;
2466
+ const elapsed = Date.now() - this.timestamp;
2467
+ const delta = this.amplitude * Math.exp(-elapsed / this.options.duration);
2468
+ if (delta > 2 || delta < -2) {
2469
+ this._scroll(this.target - delta);
2470
+ requestAnimationFrame(this._autoScroll);
2471
+ } else {
2472
+ this._scroll(this.target);
2521
2473
  }
2522
2474
  };
2523
2475
  this.el["Expressive_Carousel"] = this;
@@ -2525,56 +2477,58 @@ var Carousel = class _Carousel extends Component {
2525
2477
  ..._Carousel.defaults,
2526
2478
  ...options
2527
2479
  };
2528
- this.hasMultipleSlides = this.el.querySelectorAll(".carousel-item").length > 1;
2529
- this.showIndicators = this.options.indicators && this.hasMultipleSlides;
2530
- this.noWrap = this.options.noWrap || !this.hasMultipleSlides;
2480
+ this._flat = this.options.fullWidth || this.el.classList.contains("flat");
2481
+ if (this._flat) {
2482
+ this.el.classList.add("flat");
2483
+ this.options.fullWidth = true;
2484
+ this.options.dist = 0;
2485
+ }
2486
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
2487
+ this.options.duration = 1;
2488
+ if (!this._flat) this.options.dist = 0;
2489
+ }
2531
2490
  this.pressed = false;
2532
2491
  this.dragged = false;
2533
2492
  this.offset = this.target = 0;
2534
- this.images = [];
2535
- const firstItem = this.el.querySelector(".carousel-item");
2536
- if (!firstItem) {
2493
+ this.images = this._collectItems();
2494
+ if (!this.images.length) {
2537
2495
  console.error("Carousel: no .carousel-item elements to show");
2538
2496
  return;
2539
2497
  }
2540
- this.itemWidth = firstItem.clientWidth;
2541
- this.itemHeight = firstItem.clientHeight;
2542
- this.dim = this.itemWidth * 2 + this.options.padding || 1;
2543
- if (this.options.fullWidth) {
2544
- this.options.dist = 0;
2545
- this._setCarouselHeight();
2546
- if (this.showIndicators) {
2547
- this.el.querySelector(".carousel-fixed-item")?.classList.add("with-indicators");
2548
- }
2549
- }
2550
- this._indicators = document.createElement("ul");
2551
- this._indicators.classList.add("indicators");
2552
- this.el.querySelectorAll(".carousel-item").forEach((item, i) => {
2553
- this.images.push(item);
2554
- if (this.showIndicators) {
2555
- const indicator = document.createElement("li");
2556
- indicator.classList.add("indicator-item");
2557
- indicator.tabIndex = 0;
2558
- if (i === 0) {
2559
- indicator.classList.add("active");
2560
- }
2561
- this._indicators.appendChild(indicator);
2562
- }
2563
- });
2564
- if (this.showIndicators) this.el.appendChild(this._indicators);
2498
+ this.hasMultipleSlides = this.images.length > 1;
2499
+ this.showIndicators = this.options.indicators && this.hasMultipleSlides;
2500
+ this.noWrap = this.options.noWrap || !this.hasMultipleSlides || this._flat;
2565
2501
  this.count = this.images.length;
2566
2502
  this.options.numVisible = Math.min(this.count, this.options.numVisible);
2503
+ this.images.forEach((item) => item.classList.add("carousel-item"));
2504
+ if (this._flat) this._wrapTrack();
2505
+ const firstItem = this.images[0];
2506
+ this.itemWidth = firstItem.clientWidth || this.el.clientWidth || 1;
2507
+ this.itemHeight = firstItem.clientHeight || this.el.clientHeight || 1;
2508
+ this.dim = this.itemWidth * 2 + this.options.padding || 1;
2509
+ if (this.showIndicators) this._setupIndicators();
2510
+ this.el.tabIndex = this.el.tabIndex >= 0 ? this.el.tabIndex : 0;
2511
+ this.el.setAttribute("aria-roledescription", "carousel");
2567
2512
  this._setupEventHandlers();
2568
- this._scroll(this.offset);
2513
+ this._started = true;
2514
+ if (this._flat) {
2515
+ const start = Math.max(
2516
+ 0,
2517
+ this.images.findIndex((el2) => el2.classList.contains("active"))
2518
+ );
2519
+ this.center = start;
2520
+ this._syncActive(start, false);
2521
+ this._scrollToIndex(start, false);
2522
+ } else {
2523
+ this._scroll(this.offset);
2524
+ }
2525
+ }
2526
+ get _scroller() {
2527
+ return this._trackEl ?? this.el;
2569
2528
  }
2570
2529
  static get defaults() {
2571
2530
  return _defaults7;
2572
2531
  }
2573
- /**
2574
- * Initializes instances of Carousel.
2575
- * @param els HTML elements.
2576
- * @param options Component options.
2577
- */
2578
2532
  static init(els, options = {}) {
2579
2533
  return super.init(els, options, _Carousel);
2580
2534
  }
@@ -2582,81 +2536,104 @@ var Carousel = class _Carousel extends Component {
2582
2536
  return el["Expressive_Carousel"];
2583
2537
  }
2584
2538
  destroy() {
2585
- this._removeEventHandlers();
2539
+ if (this._started) this._teardown();
2586
2540
  this.el["Expressive_Carousel"] = void 0;
2587
2541
  }
2542
+ _collectItems() {
2543
+ const explicit = Array.from(this.el.children).filter(
2544
+ (el) => el instanceof HTMLElement && el.classList.contains("carousel-item")
2545
+ );
2546
+ if (explicit.length) return explicit;
2547
+ return Array.from(this.el.children).filter((el) => {
2548
+ if (!(el instanceof HTMLElement)) return false;
2549
+ if (el.classList.contains("indicators") || el.classList.contains("carousel-fixed-item")) {
2550
+ return false;
2551
+ }
2552
+ return el.tagName !== "NAV";
2553
+ });
2554
+ }
2555
+ _setupIndicators() {
2556
+ const existing = Array.from(this.el.children).find(
2557
+ (el) => el instanceof HTMLElement && el.classList.contains("indicators")
2558
+ );
2559
+ this._indicators = existing ?? document.createElement("nav");
2560
+ this._ownIndicators = !existing;
2561
+ this._indicators.classList.add("indicators");
2562
+ this._indicators.setAttribute("aria-label", "Slides");
2563
+ this._indicators.replaceChildren();
2564
+ this.images.forEach((_, i) => {
2565
+ const button = document.createElement("button");
2566
+ button.type = "button";
2567
+ button.classList.add("indicator-item");
2568
+ if (i === 0) {
2569
+ button.classList.add("active");
2570
+ button.setAttribute("aria-current", "true");
2571
+ }
2572
+ button.setAttribute("aria-label", `Slide ${i + 1}`);
2573
+ this._indicators.appendChild(button);
2574
+ });
2575
+ if (this._ownIndicators) this.el.appendChild(this._indicators);
2576
+ if (this._flat) {
2577
+ this.el.querySelector(".carousel-fixed-item")?.classList.add("with-indicators");
2578
+ }
2579
+ }
2588
2580
  _setupEventHandlers() {
2589
- if (typeof window.ontouchstart !== "undefined") {
2590
- this.el.addEventListener("touchstart", this._handleCarouselTap);
2591
- this.el.addEventListener("touchmove", this._handleCarouselDrag);
2592
- this.el.addEventListener("touchend", this._handleCarouselRelease);
2593
- }
2594
- this.el.addEventListener("mousedown", this._handleCarouselTap);
2595
- this.el.addEventListener("mousemove", this._handleCarouselDrag);
2596
- this.el.addEventListener("mouseup", this._handleCarouselRelease);
2597
- this.el.addEventListener("mouseleave", this._handleCarouselRelease);
2598
- this.el.addEventListener("click", this._handleCarouselClick);
2581
+ this.el.addEventListener("keydown", this._handleKeydown);
2599
2582
  if (this.showIndicators && this._indicators) {
2600
- this._indicators.querySelectorAll(".indicator-item").forEach((el) => {
2601
- el.addEventListener("click", this._handleIndicatorClick);
2602
- el.addEventListener("keypress", this._handleIndicatorKeyPress);
2603
- });
2583
+ this._indicators.addEventListener("click", this._handleIndicatorClick);
2584
+ }
2585
+ _Carousel._live.add(this);
2586
+ if (!_Carousel._resizeListening) {
2587
+ window.addEventListener("resize", _Carousel._onResize, { passive: true });
2588
+ _Carousel._resizeListening = true;
2589
+ }
2590
+ if (this._flat) {
2591
+ this._scroller.addEventListener("scroll", this._handleFlatScroll, { passive: true });
2592
+ return;
2604
2593
  }
2605
- window.addEventListener("resize", this._handleThrottledResize);
2594
+ this.el.addEventListener("pointerdown", this._handleCarouselTap);
2595
+ this.el.addEventListener("pointermove", this._handleCarouselDrag);
2596
+ this.el.addEventListener("pointerup", this._handleCarouselRelease);
2597
+ this.el.addEventListener("pointercancel", this._handleCarouselRelease);
2598
+ this.el.addEventListener("click", this._handleCarouselClick);
2606
2599
  }
2607
2600
  _removeEventHandlers() {
2608
- if (typeof window.ontouchstart !== "undefined") {
2609
- this.el.removeEventListener("touchstart", this._handleCarouselTap);
2610
- this.el.removeEventListener("touchmove", this._handleCarouselDrag);
2611
- this.el.removeEventListener("touchend", this._handleCarouselRelease);
2612
- }
2613
- this.el.removeEventListener("mousedown", this._handleCarouselTap);
2614
- this.el.removeEventListener("mousemove", this._handleCarouselDrag);
2615
- this.el.removeEventListener("mouseup", this._handleCarouselRelease);
2616
- this.el.removeEventListener("mouseleave", this._handleCarouselRelease);
2601
+ this.el.removeEventListener("keydown", this._handleKeydown);
2602
+ if (this._indicators) {
2603
+ this._indicators.removeEventListener("click", this._handleIndicatorClick);
2604
+ }
2605
+ this._scroller.removeEventListener("scroll", this._handleFlatScroll);
2606
+ this.el.removeEventListener("pointerdown", this._handleCarouselTap);
2607
+ this.el.removeEventListener("pointermove", this._handleCarouselDrag);
2608
+ this.el.removeEventListener("pointerup", this._handleCarouselRelease);
2609
+ this.el.removeEventListener("pointercancel", this._handleCarouselRelease);
2617
2610
  this.el.removeEventListener("click", this._handleCarouselClick);
2618
- if (this.showIndicators && this._indicators) {
2619
- this._indicators.querySelectorAll(".indicator-item").forEach((el) => {
2620
- el.removeEventListener("click", this._handleIndicatorClick);
2621
- });
2611
+ _Carousel._live.delete(this);
2612
+ if (_Carousel._live.size === 0 && _Carousel._resizeListening) {
2613
+ window.removeEventListener("resize", _Carousel._onResize);
2614
+ _Carousel._resizeListening = false;
2622
2615
  }
2623
- window.removeEventListener("resize", this._handleThrottledResize);
2624
2616
  }
2625
- _setCarouselHeight(imageOnly = false) {
2626
- const firstSlide = this.el.querySelector(".carousel-item.active") ? this.el.querySelector(".carousel-item.active") : this.el.querySelector(".carousel-item");
2627
- const firstImage = firstSlide.querySelector("img");
2628
- if (firstImage) {
2629
- if (firstImage.complete) {
2630
- const imageHeight = firstImage.clientHeight;
2631
- if (imageHeight > 0) {
2632
- this.el.style.height = imageHeight + "px";
2633
- } else {
2634
- const naturalWidth = firstImage.naturalWidth;
2635
- const naturalHeight = firstImage.naturalHeight;
2636
- const adjustedHeight = this.el.clientWidth / naturalWidth * naturalHeight;
2637
- this.el.style.height = adjustedHeight + "px";
2638
- }
2639
- } else {
2640
- firstImage.addEventListener("load", () => {
2641
- this.el.style.height = firstImage.offsetHeight + "px";
2642
- });
2643
- }
2644
- } else if (!imageOnly) {
2645
- const slideHeight = firstSlide.clientHeight;
2646
- this.el.style.height = slideHeight + "px";
2647
- }
2617
+ _teardown() {
2618
+ this._removeEventHandlers();
2619
+ if (this._trackRaf !== null) cancelAnimationFrame(this._trackRaf);
2620
+ window.clearTimeout(this.scrollingTimeout);
2621
+ if (this._ownIndicators) this._indicators?.remove();
2622
+ this._unwrapTrack();
2623
+ this.images.forEach((el) => {
2624
+ el.style.transform = "";
2625
+ el.style.zIndex = "";
2626
+ el.style.opacity = "";
2627
+ el.style.visibility = "";
2628
+ });
2648
2629
  }
2649
2630
  _xpos(e) {
2650
- if (e.type.startsWith("touch") && e.targetTouches.length >= 1) {
2651
- return e.targetTouches[0].clientX;
2652
- }
2653
- return e.clientX;
2631
+ if ("clientX" in e) return e.clientX;
2632
+ return 0;
2654
2633
  }
2655
2634
  _ypos(e) {
2656
- if (e.type.startsWith("touch") && e.targetTouches.length >= 1) {
2657
- return e.targetTouches[0].clientY;
2658
- }
2659
- return e.clientY;
2635
+ if ("clientY" in e) return e.clientY;
2636
+ return 0;
2660
2637
  }
2661
2638
  _wrap(x) {
2662
2639
  return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + x % this.count) : x;
@@ -2665,18 +2642,20 @@ var Carousel = class _Carousel extends Component {
2665
2642
  if (!this.el.classList.contains("scrolling")) {
2666
2643
  this.el.classList.add("scrolling");
2667
2644
  }
2668
- if (this.scrollingTimeout != null) {
2669
- clearTimeout(this.scrollingTimeout);
2670
- }
2645
+ window.clearTimeout(this.scrollingTimeout);
2671
2646
  this.scrollingTimeout = setTimeout(() => {
2672
2647
  this.el.classList.remove("scrolling");
2673
2648
  }, this.options.duration);
2674
2649
  this.offset = typeof x === "number" ? x : this.offset;
2675
2650
  this.center = Math.floor((this.offset + this.dim / 2) / this.dim);
2676
- const half = this.count >> 1, delta = this.offset - this.center * this.dim, dir = delta < 0 ? 1 : -1, tween = -dir * delta * 2 / this.dim;
2677
- let i, el, alignment, zTranslation, tweenedOpacity, centerTweenedOpacity;
2651
+ const half = this.count >> 1;
2652
+ const delta = this.offset - this.center * this.dim;
2653
+ const dir = delta < 0 ? 1 : -1;
2654
+ const tween = -dir * delta * 2 / this.dim;
2678
2655
  const lastCenter = this.center;
2679
2656
  const numVisibleOffset = 1 / this.options.numVisible;
2657
+ let alignment;
2658
+ let centerTweenedOpacity;
2680
2659
  if (this.options.fullWidth) {
2681
2660
  alignment = "translateX(0)";
2682
2661
  centerTweenedOpacity = 1;
@@ -2685,26 +2664,17 @@ var Carousel = class _Carousel extends Component {
2685
2664
  alignment += "translateY(" + (this.el.clientHeight - this.itemHeight) / 2 + "px)";
2686
2665
  centerTweenedOpacity = 1 - numVisibleOffset * tween;
2687
2666
  }
2688
- if (this.showIndicators) {
2689
- const diff = this.center % this.count;
2690
- const activeIndicator = this._indicators.querySelector(".indicator-item.active");
2691
- const activeIndicatorIndex = [...activeIndicator.parentNode.children].indexOf(
2692
- activeIndicator
2693
- );
2694
- if (activeIndicatorIndex !== diff) {
2695
- activeIndicator.classList.remove("active");
2696
- const pos = diff < 0 ? this.count + diff : diff;
2697
- this._indicators.querySelectorAll(".indicator-item")[pos].classList.add("active");
2698
- }
2699
- }
2667
+ this._paintIndicators(this.center);
2700
2668
  if (!this.noWrap || this.center >= 0 && this.center < this.count) {
2701
- el = this.images[this._wrap(this.center)];
2702
- if (!el.classList.contains("active")) {
2669
+ const el = this.images[this._wrap(this.center)];
2670
+ if (el && !el.classList.contains("active")) {
2703
2671
  this.el.querySelector(".carousel-item.active")?.classList.remove("active");
2704
2672
  el.classList.add("active");
2705
2673
  }
2706
2674
  }
2707
- for (i = 1; i <= half; ++i) {
2675
+ for (let i = 1; i <= half; ++i) {
2676
+ let zTranslation;
2677
+ let tweenedOpacity;
2708
2678
  if (this.options.fullWidth) {
2709
2679
  zTranslation = this.options.dist;
2710
2680
  tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1;
@@ -2713,7 +2683,7 @@ var Carousel = class _Carousel extends Component {
2713
2683
  tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir);
2714
2684
  }
2715
2685
  if (!this.noWrap || this.center + i < this.count) {
2716
- el = this.images[this._wrap(this.center + i)];
2686
+ const el = this.images[this._wrap(this.center + i)];
2717
2687
  const transformString = `${alignment} translateX(${this.options.shift + (this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`;
2718
2688
  this._updateItemStyle(el, tweenedOpacity, -i, transformString);
2719
2689
  }
@@ -2725,32 +2695,113 @@ var Carousel = class _Carousel extends Component {
2725
2695
  tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir);
2726
2696
  }
2727
2697
  if (!this.noWrap || this.center - i >= 0) {
2728
- el = this.images[this._wrap(this.center - i)];
2698
+ const el = this.images[this._wrap(this.center - i)];
2729
2699
  const transformString = `${alignment} translateX(${-this.options.shift + (-this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`;
2730
2700
  this._updateItemStyle(el, tweenedOpacity, -i, transformString);
2731
2701
  }
2732
2702
  }
2733
2703
  if (!this.noWrap || this.center >= 0 && this.center < this.count) {
2734
- el = this.images[this._wrap(this.center)];
2704
+ const el = this.images[this._wrap(this.center)];
2735
2705
  const transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * this.options.shift * tween}px) translateZ(${this.options.dist * tween}px)`;
2736
2706
  this._updateItemStyle(el, centerTweenedOpacity, 0, transformString);
2737
2707
  }
2738
- const _currItem = this.el.querySelectorAll(".carousel-item")[this._wrap(this.center)];
2708
+ const currItem = this.images[this._wrap(this.center)];
2709
+ this._syncA11y(this._wrap(this.center));
2739
2710
  if (lastCenter !== this.center && typeof this.options.onCycleTo === "function") {
2740
- this.options.onCycleTo.call(this, _currItem, this.dragged);
2711
+ this.options.onCycleTo.call(this, currItem, this.dragged);
2741
2712
  }
2742
2713
  if (typeof this.oneTimeCallback === "function") {
2743
- this.oneTimeCallback.call(this, _currItem, this.dragged);
2714
+ this.oneTimeCallback.call(this, currItem, this.dragged);
2744
2715
  this.oneTimeCallback = null;
2745
2716
  }
2746
2717
  }
2747
2718
  _updateItemStyle(el, opacity, zIndex, transform) {
2719
+ if (!el) return;
2748
2720
  el.style.transform = transform;
2749
2721
  el.style.zIndex = zIndex.toString();
2750
2722
  el.style.opacity = opacity.toString();
2751
2723
  el.style.visibility = "visible";
2752
2724
  }
2725
+ _paintIndicators(center) {
2726
+ if (!this.showIndicators || !this._indicators) return;
2727
+ const pos = (center % this.count + this.count) % this.count;
2728
+ this._indicators.querySelectorAll(".indicator-item").forEach((el, i) => {
2729
+ const on = i === pos;
2730
+ el.classList.toggle("active", on);
2731
+ if (on) el.setAttribute("aria-current", "true");
2732
+ else el.removeAttribute("aria-current");
2733
+ });
2734
+ }
2735
+ _syncA11y(index) {
2736
+ this.images.forEach((el, i) => {
2737
+ if (i === index) el.removeAttribute("aria-hidden");
2738
+ else el.setAttribute("aria-hidden", "true");
2739
+ });
2740
+ }
2741
+ _syncActive(index, dragged) {
2742
+ const prev = this.center;
2743
+ this.center = index;
2744
+ this.images.forEach((el, i) => el.classList.toggle("active", i === index));
2745
+ this._paintIndicators(index);
2746
+ this._syncA11y(index);
2747
+ const curr = this.images[index];
2748
+ if (prev !== index && typeof this.options.onCycleTo === "function") {
2749
+ this.options.onCycleTo.call(this, curr, dragged);
2750
+ }
2751
+ if (typeof this.oneTimeCallback === "function") {
2752
+ this.oneTimeCallback.call(this, curr, dragged);
2753
+ this.oneTimeCallback = null;
2754
+ }
2755
+ }
2756
+ _wrapTrack() {
2757
+ const track = document.createElement("div");
2758
+ track.className = "carousel-track";
2759
+ this.images[0].before(track);
2760
+ this.images.forEach((el) => track.appendChild(el));
2761
+ this._trackEl = track;
2762
+ }
2763
+ _unwrapTrack() {
2764
+ if (!this._trackEl) return;
2765
+ this.images.forEach((el) => this.el.insertBefore(el, this._trackEl));
2766
+ this._trackEl.remove();
2767
+ this._trackEl = null;
2768
+ }
2769
+ _nearestIndex() {
2770
+ const left = this._scroller.scrollLeft;
2771
+ let best = 0;
2772
+ let bestDist = Infinity;
2773
+ this.images.forEach((el, i) => {
2774
+ const dist = Math.abs(el.offsetLeft - left);
2775
+ if (dist < bestDist) {
2776
+ bestDist = dist;
2777
+ best = i;
2778
+ }
2779
+ });
2780
+ return best;
2781
+ }
2782
+ _scrollToIndex(n, smooth = true) {
2783
+ const el = this.images[n];
2784
+ if (!el) return;
2785
+ const left = el.offsetLeft;
2786
+ if (Math.abs(this._scroller.scrollLeft - left) < 1) {
2787
+ this._syncActive(n, false);
2788
+ return;
2789
+ }
2790
+ this._ignoreScroll = true;
2791
+ this._scroller.scrollTo({ left, behavior: smooth ? "smooth" : "auto" });
2792
+ const done = () => {
2793
+ this._ignoreScroll = false;
2794
+ };
2795
+ this._scroller.addEventListener("scrollend", done, { once: true });
2796
+ window.setTimeout(done, this.options.duration + 350);
2797
+ }
2753
2798
  _cycleTo(n, callback = null) {
2799
+ if (this._flat) {
2800
+ if (typeof callback === "function") this.oneTimeCallback = callback;
2801
+ this._syncActive(n, false);
2802
+ this._scrollToIndex(n);
2803
+ return;
2804
+ }
2754
2805
  let diff = this.center % this.count - n;
2755
2806
  if (!this.noWrap) {
2756
2807
  if (diff < 0) {
@@ -2778,14 +2829,8 @@ var Carousel = class _Carousel extends Component {
2778
2829
  requestAnimationFrame(this._autoScroll);
2779
2830
  }
2780
2831
  }
2781
- /**
2782
- * Move carousel to next slide or go forward a given amount of slides.
2783
- * @param n How many times the carousel slides.
2784
- */
2785
2832
  next(n = 1) {
2786
- if (n === void 0 || isNaN(n)) {
2787
- n = 1;
2788
- }
2833
+ if (n === void 0 || isNaN(n)) n = 1;
2789
2834
  let index = this.center + n;
2790
2835
  if (index >= this.count || index < 0) {
2791
2836
  if (this.noWrap) return;
@@ -2793,14 +2838,8 @@ var Carousel = class _Carousel extends Component {
2793
2838
  }
2794
2839
  this._cycleTo(index);
2795
2840
  }
2796
- /**
2797
- * Move carousel to previous slide or go back a given amount of slides.
2798
- * @param n How many times the carousel slides.
2799
- */
2800
2841
  prev(n = 1) {
2801
- if (n === void 0 || isNaN(n)) {
2802
- n = 1;
2803
- }
2842
+ if (n === void 0 || isNaN(n)) n = 1;
2804
2843
  let index = this.center - n;
2805
2844
  if (index >= this.count || index < 0) {
2806
2845
  if (this.noWrap) return;
@@ -2808,15 +2847,8 @@ var Carousel = class _Carousel extends Component {
2808
2847
  }
2809
2848
  this._cycleTo(index);
2810
2849
  }
2811
- /**
2812
- * Move carousel to nth slide.
2813
- * @param n Index of slide.
2814
- * @param callback "onCycleTo" optional callback.
2815
- */
2816
2850
  set(n, callback) {
2817
- if (n === void 0 || isNaN(n)) {
2818
- n = 0;
2819
- }
2851
+ if (n === void 0 || isNaN(n)) n = 0;
2820
2852
  if (n > this.count || n < 0) {
2821
2853
  if (this.noWrap) return;
2822
2854
  n = this._wrap(n);
@@ -2824,6 +2856,12 @@ var Carousel = class _Carousel extends Component {
2824
2856
  this._cycleTo(n, callback);
2825
2857
  }
2826
2858
  };
2859
+ _Carousel._live = /* @__PURE__ */ new Set();
2860
+ _Carousel._resizeListening = false;
2861
+ _Carousel._onResize = Utils.throttle(() => {
2862
+ _Carousel._live.forEach((c) => c._handleResize());
2863
+ }, 200);
2864
+ var Carousel = _Carousel;
2827
2865
 
2828
2866
  // src/ts/components/characterCounter.ts
2829
2867
  var _defaults8 = Object.freeze({});
@@ -2906,84 +2944,55 @@ var _defaults9 = {
2906
2944
  onOpenStart: null,
2907
2945
  onOpenEnd: null,
2908
2946
  onCloseStart: null,
2909
- onCloseEnd: null,
2910
- inDuration: 300,
2911
- outDuration: 300
2947
+ onCloseEnd: null
2912
2948
  };
2913
2949
  var Collapsible = class _Collapsible extends Component {
2914
2950
  constructor(el, options) {
2915
2951
  super(el, options, _Collapsible);
2916
- this._handleCollapsibleClick = (e) => {
2917
- const header = e.target.closest(".collapsible-header");
2918
- if (e.target && header) {
2919
- const collapsible = header.closest(".collapsible");
2920
- if (collapsible !== this.el) return;
2921
- const li = header.closest("li");
2922
- const isActive = li.classList.contains("active");
2923
- const index = [...li.parentNode.children].indexOf(li);
2924
- if (isActive) this.close(index);
2925
- else this.open(index);
2926
- }
2927
- };
2928
- this._handleCollapsibleKeydown = (e) => {
2929
- if (Utils.keys.ENTER.includes(e.key)) {
2930
- this._handleCollapsibleClick(e);
2931
- }
2932
- };
2952
+ this._items = [];
2953
+ this._endTimers = [];
2954
+ this._wrappedBodies = [];
2933
2955
  /**
2934
2956
  * Open collapsible section.
2935
- * @param n Nth section to open.
2957
+ * @param index 0-based index of the section to open.
2936
2958
  */
2937
2959
  this.open = (index) => {
2938
- const listItems = Array.from(this.el.children).filter((c) => c.tagName === "LI");
2939
- const li = listItems[index];
2940
- if (li && !li.classList.contains("active")) {
2941
- if (typeof this.options.onOpenStart === "function") {
2942
- this.options.onOpenStart.call(this, li);
2943
- }
2944
- if (this.options.accordion) {
2945
- const activeLis = listItems.filter((li2) => li2.classList.contains("active"));
2946
- activeLis.forEach((activeLi) => {
2947
- const index2 = listItems.indexOf(activeLi);
2948
- this.close(index2);
2949
- });
2950
- }
2951
- li.classList.add("active");
2952
- this._animateIn(index);
2960
+ const item = this._items[index];
2961
+ if (!item || this._isOpen(item)) return;
2962
+ if (this.options.accordion) {
2963
+ this._items.forEach((other, i) => {
2964
+ if (i !== index && this._isOpen(other)) this.close(i);
2965
+ });
2953
2966
  }
2967
+ this._setOpen(item, true);
2954
2968
  };
2955
2969
  /**
2956
2970
  * Close collapsible section.
2957
- * @param n Nth section to close.
2971
+ * @param index 0-based index of the section to close.
2958
2972
  */
2959
2973
  this.close = (index) => {
2960
- const li = Array.from(this.el.children).filter((c) => c.tagName === "LI")[index];
2961
- if (li && li.classList.contains("active")) {
2962
- if (typeof this.options.onCloseStart === "function") {
2963
- this.options.onCloseStart.call(this, li);
2964
- }
2965
- li.classList.remove("active");
2966
- this._animateOut(index);
2967
- }
2974
+ const item = this._items[index];
2975
+ if (!item || !this._isOpen(item)) return;
2976
+ this._setOpen(item, false);
2977
+ };
2978
+ this._handleToggle = (e) => {
2979
+ const item = e.target;
2980
+ if (!(item instanceof HTMLDetailsElement)) return;
2981
+ if (!this._items.includes(item)) return;
2982
+ this._notify(item, item.open);
2968
2983
  };
2969
2984
  this.el["Expressive_Collapsible"] = this;
2985
+ const accordion = options.accordion !== void 0 ? options.accordion : !el.classList.contains("expandable");
2970
2986
  this.options = {
2971
2987
  ..._Collapsible.defaults,
2972
- ...options
2988
+ ...options,
2989
+ accordion
2973
2990
  };
2974
- this._headers = Array.from(this.el.querySelectorAll("li > .collapsible-header"));
2975
- this._headers.forEach((el2) => el2.tabIndex = 0);
2991
+ this._groupName = el.id ? `collapsible-${el.id}` : `collapsible-${Utils.guid()}`;
2992
+ this._items = this._collectItems();
2993
+ this._wrapDetailsBodies();
2994
+ this._setupItems();
2976
2995
  this._setupEventHandlers();
2977
- const activeBodies = Array.from(
2978
- this.el.querySelectorAll("li.active > .collapsible-body")
2979
- );
2980
- if (this.options.accordion) {
2981
- if (activeBodies.length > 0) {
2982
- this._setExpanded(activeBodies[0]);
2983
- }
2984
- } else {
2985
- activeBodies.forEach((el2) => this._setExpanded(el2));
2986
- }
2987
2996
  }
2988
2997
  static get defaults() {
2989
2998
  return _defaults9;
@@ -3001,48 +3010,99 @@ var Collapsible = class _Collapsible extends Component {
3001
3010
  }
3002
3011
  destroy() {
3003
3012
  this._removeEventHandlers();
3013
+ this._endTimers.forEach((id) => clearTimeout(id));
3014
+ this._endTimers = [];
3015
+ this._unwrapDetailsBodies();
3004
3016
  this.el["Expressive_Collapsible"] = void 0;
3005
3017
  }
3006
- _setupEventHandlers() {
3007
- this.el.addEventListener("click", this._handleCollapsibleClick);
3008
- this._headers.forEach(
3009
- (header) => header.addEventListener("keydown", this._handleCollapsibleKeydown)
3010
- );
3018
+ _collectItems() {
3019
+ return Array.from(this.el.querySelectorAll(":scope > details"));
3011
3020
  }
3012
- _removeEventHandlers() {
3013
- this.el.removeEventListener("click", this._handleCollapsibleClick);
3014
- this._headers.forEach(
3015
- (header) => header.removeEventListener("keydown", this._handleCollapsibleKeydown)
3016
- );
3021
+ _setupItems() {
3022
+ if (this.options.accordion) {
3023
+ this._items.forEach((item) => {
3024
+ if (item instanceof HTMLDetailsElement && !item.getAttribute("name")) {
3025
+ item.setAttribute("name", this._groupName);
3026
+ }
3027
+ });
3028
+ }
3029
+ const opened = this._items.filter((item) => this._isOpen(item));
3030
+ if (this.options.accordion && opened.length > 1) {
3031
+ opened.slice(1).forEach((item) => {
3032
+ if (item instanceof HTMLDetailsElement) item.open = false;
3033
+ });
3034
+ }
3017
3035
  }
3018
- _setExpanded(li) {
3019
- li.style.maxHeight = li.scrollHeight + "px";
3036
+ _isOpen(item) {
3037
+ return item instanceof HTMLDetailsElement && item.open;
3020
3038
  }
3021
- _animateIn(index) {
3022
- const li = this.el.children[index];
3023
- if (!li) return;
3024
- const body = li.querySelector(".collapsible-body");
3025
- const duration = this.options.inDuration;
3026
- body.style.transition = `max-height ${duration}ms ease-out`;
3027
- this._setExpanded(body);
3028
- setTimeout(() => {
3029
- if (typeof this.options.onOpenEnd === "function") {
3030
- this.options.onOpenEnd.call(this, li);
3031
- }
3032
- }, duration);
3039
+ _setOpen(item, open) {
3040
+ if (item instanceof HTMLDetailsElement) item.open = open;
3033
3041
  }
3034
- _animateOut(index) {
3035
- const li = this.el.children[index];
3036
- if (!li) return;
3037
- const body = li.querySelector(".collapsible-body");
3038
- const duration = this.options.outDuration;
3039
- body.style.transition = `max-height ${duration}ms ease-out`;
3040
- body.style.maxHeight = "0";
3041
- setTimeout(() => {
3042
- if (typeof this.options.onCloseEnd === "function") {
3043
- this.options.onCloseEnd.call(this, li);
3042
+ _wrapDetailsBodies() {
3043
+ this._items.forEach((item) => {
3044
+ if (!(item instanceof HTMLDetailsElement)) return;
3045
+ if (item.querySelector(":scope > :not(summary)")) {
3046
+ const already = Array.from(item.children).filter((c) => c.tagName !== "SUMMARY");
3047
+ if (already.length === 1 && already[0].tagName === "DIV") {
3048
+ this._wrappedBodies.push(already[0]);
3049
+ return;
3050
+ }
3044
3051
  }
3045
- }, duration);
3052
+ const body = document.createElement("div");
3053
+ Array.from(item.childNodes).forEach((node) => {
3054
+ if (node instanceof HTMLElement && node.tagName === "SUMMARY") return;
3055
+ body.appendChild(node);
3056
+ });
3057
+ item.appendChild(body);
3058
+ this._wrappedBodies.push(body);
3059
+ });
3060
+ }
3061
+ _unwrapDetailsBodies() {
3062
+ this._wrappedBodies.forEach((body) => {
3063
+ const parent = body.parentNode;
3064
+ if (!parent) return;
3065
+ while (body.firstChild) parent.insertBefore(body.firstChild, body);
3066
+ body.remove();
3067
+ });
3068
+ this._wrappedBodies = [];
3069
+ }
3070
+ _bodyOf(item) {
3071
+ return item.querySelector(":scope > :not(summary)");
3072
+ }
3073
+ _setupEventHandlers() {
3074
+ this.el.addEventListener("toggle", this._handleToggle, true);
3075
+ }
3076
+ _removeEventHandlers() {
3077
+ this.el.removeEventListener("toggle", this._handleToggle, true);
3078
+ }
3079
+ _notify(item, opening) {
3080
+ const start = opening ? this.options.onOpenStart : this.options.onCloseStart;
3081
+ if (typeof start === "function") start.call(this, item);
3082
+ const end = opening ? this.options.onOpenEnd : this.options.onCloseEnd;
3083
+ if (typeof end !== "function") return;
3084
+ const target = this._bodyOf(item) ?? item;
3085
+ let done = false;
3086
+ const finish = () => {
3087
+ if (done) return;
3088
+ done = true;
3089
+ target.removeEventListener("transitionend", onEnd);
3090
+ end.call(this, item);
3091
+ };
3092
+ const onEnd = (ev) => {
3093
+ if (ev.target !== target) return;
3094
+ finish();
3095
+ };
3096
+ target.addEventListener("transitionend", onEnd);
3097
+ this._endTimers.push(window.setTimeout(finish, this._durationMs() + 50));
3098
+ }
3099
+ _durationMs() {
3100
+ const raw = getComputedStyle(this.el).getPropertyValue("--md-comp-collapsible-duration").trim();
3101
+ if (!raw) return 500;
3102
+ if (raw.endsWith("ms")) return parseFloat(raw);
3103
+ if (raw.endsWith("s")) return parseFloat(raw) * 1e3;
3104
+ const n = parseFloat(raw);
3105
+ return Number.isFinite(n) ? n : 500;
3046
3106
  }
3047
3107
  };
3048
3108
 
@@ -3068,6 +3128,12 @@ var FormSelect = class _FormSelect extends Component {
3068
3128
  this._selectOptionElement(virtualOption);
3069
3129
  e.stopPropagation();
3070
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
+ };
3071
3137
  this._handleInputClick = () => {
3072
3138
  if (this.dropdown && this.dropdown.isOpen) {
3073
3139
  this._setValueToInput();
@@ -3084,6 +3150,8 @@ var FormSelect = class _FormSelect extends Component {
3084
3150
  this.nativeTabIndex = this.el.tabIndex ?? -1;
3085
3151
  this.el.tabIndex = -1;
3086
3152
  this._values = [];
3153
+ this._createdWrapper = false;
3154
+ this._originalLabelFor = null;
3087
3155
  this._setupDropdown();
3088
3156
  this._setupEventHandlers();
3089
3157
  }
@@ -3105,6 +3173,7 @@ var FormSelect = class _FormSelect extends Component {
3105
3173
  this._removeEventHandlers();
3106
3174
  this.dropdown?.destroy();
3107
3175
  this._removeDropdown();
3176
+ this.el.tabIndex = this.nativeTabIndex;
3108
3177
  this.el["Expressive_FormSelect"] = void 0;
3109
3178
  }
3110
3179
  /**
@@ -3112,27 +3181,38 @@ var FormSelect = class _FormSelect extends Component {
3112
3181
  *
3113
3182
  * Assigning `select.value` from script fires no `change` event, so nothing
3114
3183
  * else syncs the visible input text or the `.selected` state on the virtual
3115
- * 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.
3116
3186
  */
3117
3187
  refresh() {
3188
+ if (!this.dropdownOptions) return;
3189
+ this._rebuildOptions();
3118
3190
  this._setValueToInput();
3119
3191
  this._setSelectedStates();
3120
3192
  }
3121
3193
  _setupEventHandlers() {
3122
- this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3123
- el.addEventListener("click", this._handleOptionClick);
3124
- el.addEventListener("keydown", this._handleOptionKeydown);
3125
- });
3194
+ this._setupOptionHandlers();
3126
3195
  this.el.addEventListener("change", this._handleSelectChange);
3127
3196
  this.input.addEventListener("click", this._handleInputClick);
3197
+ this.dropdownOptions.addEventListener("focusin", this._handleOptionFocus);
3128
3198
  }
3129
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() {
3130
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) => {
3131
3213
  el.removeEventListener("click", this._handleOptionClick);
3132
3214
  el.removeEventListener("keydown", this._handleOptionKeydown);
3133
3215
  });
3134
- this.el.removeEventListener("change", this._handleSelectChange);
3135
- this.input.removeEventListener("click", this._handleInputClick);
3136
3216
  }
3137
3217
  _arraysEqual(a, b) {
3138
3218
  if (a === b) return true;
@@ -3144,6 +3224,7 @@ var FormSelect = class _FormSelect extends Component {
3144
3224
  _selectOptionElement(virtualOption) {
3145
3225
  if (!virtualOption.classList.contains("disabled") && !virtualOption.classList.contains("optgroup")) {
3146
3226
  const value = this._values.find((value2) => value2.optionEl === virtualOption);
3227
+ if (!value) return;
3147
3228
  const previousSelectedValues = this.getSelectedValues();
3148
3229
  if (this.isMultiple) {
3149
3230
  this._toggleEntryFromArray(value);
@@ -3159,70 +3240,54 @@ var FormSelect = class _FormSelect extends Component {
3159
3240
  new Event("change", { bubbles: true, cancelable: true, composed: true })
3160
3241
  );
3161
3242
  }
3162
- if (!this.isMultiple) this.dropdown.close();
3243
+ if (!this.isMultiple) this.dropdown?.close();
3163
3244
  }
3164
3245
  _setupDropdown() {
3165
3246
  this.labelEl = this.el.labels?.[0] ?? null;
3166
- this.wrapper = document.createElement("div");
3167
- this.wrapper.classList.add("select-wrapper", "input-field");
3168
- if (this.options.classes.length > 0) {
3169
- this.wrapper.classList.add(...this.options.classes.split(" ").filter(Boolean));
3170
- }
3171
- this.el.before(this.wrapper);
3172
- const hiddenDiv = document.createElement("div");
3173
- hiddenDiv.classList.add("hide-select");
3174
- this.wrapper.append(hiddenDiv);
3175
- hiddenDiv.appendChild(this.el);
3247
+ this._setupWrapper();
3248
+ this._hideNativeSelect();
3176
3249
  if (this.el.disabled) this.wrapper.classList.add("disabled");
3177
- this.selectOptions = Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
3178
- this.dropdownOptions = document.createElement("ul");
3250
+ this.dropdownOptions = document.createElement("menu");
3179
3251
  this.dropdownOptions.id = `select-options-${Utils.guid()}`;
3180
3252
  this.dropdownOptions.setAttribute("popover", "auto");
3181
- this.dropdownOptions.classList.add("dropdown-content", "select-dropdown");
3182
3253
  this.dropdownOptions.setAttribute("role", "listbox");
3183
3254
  this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
3184
3255
  if (this.isMultiple) this.dropdownOptions.classList.add("multiple-select-dropdown");
3185
- if (this.selectOptions.length > 0) {
3186
- this.selectOptions.forEach((realOption) => {
3187
- if (realOption.tagName === "OPTION") {
3188
- const virtualOption = this._createAndAppendOptionWithIcon(
3189
- realOption,
3190
- this.isMultiple ? "multiple" : void 0
3191
- );
3192
- this._addOptionToValues(realOption, virtualOption);
3193
- } else if (realOption.tagName === "OPTGROUP") {
3194
- const groupId = "opt-group-" + Utils.guid();
3195
- const groupParent = document.createElement("li");
3196
- groupParent.classList.add("optgroup");
3197
- groupParent.tabIndex = -1;
3198
- groupParent.setAttribute("role", "group");
3199
- groupParent.setAttribute("aria-labelledby", groupId);
3200
- const groupLabel = document.createElement("span");
3201
- groupLabel.id = groupId;
3202
- groupLabel.setAttribute("role", "presentation");
3203
- groupLabel.textContent = realOption.getAttribute("label") ?? "";
3204
- groupParent.replaceChildren(groupLabel);
3205
- this.dropdownOptions.append(groupParent);
3206
- const groupChildren = [];
3207
- const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3208
- selectOptions.forEach((realOption2) => {
3209
- const virtualOption = this._createAndAppendOptionWithIcon(
3210
- realOption2,
3211
- "optgroup-option"
3212
- );
3213
- const childId = "opt-child-" + Utils.guid();
3214
- virtualOption.id = childId;
3215
- groupChildren.push(childId);
3216
- this._addOptionToValues(realOption2, virtualOption);
3217
- });
3218
- groupParent.setAttribute("aria-owns", groupChildren.join(" "));
3219
- }
3220
- });
3221
- }
3256
+ this._buildOptions();
3222
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() {
3223
3288
  this.input = document.createElement("input");
3224
- this.input.id = "m_select-input-" + Utils.guid();
3225
- this.input.classList.add("select-dropdown", "dropdown-trigger");
3289
+ this.input.id = "select-input-" + Utils.guid();
3290
+ this.input.classList.add("dropdown-trigger");
3226
3291
  this.input.type = "text";
3227
3292
  this.input.readOnly = true;
3228
3293
  this.input.setAttribute("data-target", this.dropdownOptions.id);
@@ -3236,71 +3301,131 @@ var FormSelect = class _FormSelect extends Component {
3236
3301
  if (attr.name.startsWith("aria-")) this.input.setAttribute(attr.name, attr.value);
3237
3302
  }
3238
3303
  this.input.setAttribute("role", "combobox");
3304
+ this.input.setAttribute("aria-haspopup", "listbox");
3239
3305
  this.input.ariaExpanded = "false";
3240
- this.input.setAttribute("aria-owns", this.dropdownOptions.id);
3241
3306
  this.input.setAttribute("aria-controls", this.dropdownOptions.id);
3242
3307
  this.input.placeholder = " ";
3308
+ if (this.labelEl) {
3309
+ this._originalLabelFor = this.labelEl.htmlFor;
3310
+ this.labelEl.htmlFor = this.input.id;
3311
+ }
3243
3312
  this.wrapper.prepend(this.input);
3244
3313
  this._setValueToInput();
3245
- const dropdownIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
3246
- dropdownIcon.classList.add("caret");
3247
- dropdownIcon.setAttribute("height", "24");
3248
- dropdownIcon.setAttribute("width", "24");
3249
- dropdownIcon.setAttribute("viewBox", "0 0 24 24");
3250
- dropdownIcon.ariaHidden = "true";
3251
- dropdownIcon.innerHTML = `<path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/>`;
3252
- this.wrapper.prepend(dropdownIcon);
3253
- if (!this.el.disabled) {
3254
- const dropdownOptions = { ...this.options.dropdownOptions };
3255
- dropdownOptions.coverTrigger = false;
3256
- const userOnOpenEnd = dropdownOptions.onOpenEnd;
3257
- const userOnCloseEnd = dropdownOptions.onCloseEnd;
3258
- dropdownOptions.onOpenEnd = () => {
3259
- const selectedOption = this.dropdownOptions.querySelector(".selected");
3260
- if (selectedOption) {
3261
- Utils.keyDown = true;
3262
- this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(
3263
- selectedOption
3264
- );
3265
- this.dropdown._focusFocusedItem();
3266
- Utils.keyDown = false;
3267
- if (this.dropdown.isScrollable) {
3268
- let scrollOffset = selectedOption.getBoundingClientRect().top - this.dropdownOptions.getBoundingClientRect().top;
3269
- scrollOffset -= this.dropdownOptions.clientHeight / 2;
3270
- this.dropdownOptions.scrollTop = scrollOffset;
3271
- }
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;
3272
3338
  }
3273
- this.input.ariaExpanded = "true";
3274
- if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3275
- userOnOpenEnd.call(this.dropdown, this.el);
3276
- };
3277
- dropdownOptions.onCloseEnd = () => {
3278
- this.input.ariaExpanded = "false";
3279
- if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3280
- userOnCloseEnd.call(this.dropdown, this.el);
3281
- };
3282
- dropdownOptions.closeOnClick = false;
3283
- this.dropdown = Dropdown.init(this.input, dropdownOptions);
3284
- }
3285
- this._setSelectedStates();
3286
- 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();
3287
3397
  }
3288
3398
  _addOptionToValues(realOption, virtualOption) {
3289
3399
  this._values.push({ el: realOption, optionEl: virtualOption });
3290
3400
  }
3291
3401
  _removeDropdown() {
3292
- this.wrapper.querySelector(".caret").remove();
3293
- this.input.remove();
3294
- this.dropdownOptions.remove();
3295
- this.wrapper.before(this.el);
3296
- 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
+ }
3297
3419
  }
3298
3420
  _createAndAppendOptionWithIcon(realOption, type) {
3299
3421
  const li = document.createElement("li");
3422
+ li.id = "select-option-" + Utils.guid();
3300
3423
  li.setAttribute("role", "option");
3424
+ li.tabIndex = 0;
3301
3425
  if (realOption.disabled) {
3302
3426
  li.classList.add("disabled");
3303
3427
  li.ariaDisabled = "true";
3428
+ li.tabIndex = -1;
3304
3429
  }
3305
3430
  if (type === "optgroup-option") li.classList.add(type);
3306
3431
  const optionText = realOption.textContent;
@@ -3309,6 +3434,7 @@ var FormSelect = class _FormSelect extends Component {
3309
3434
  const label = document.createElement("label");
3310
3435
  const checkbox = document.createElement("input");
3311
3436
  checkbox.type = "checkbox";
3437
+ checkbox.tabIndex = -1;
3312
3438
  const labelText = document.createElement("span");
3313
3439
  labelText.textContent = optionText;
3314
3440
  label.append(checkbox, labelText);
@@ -3372,7 +3498,7 @@ var FormSelect = class _FormSelect extends Component {
3372
3498
  if (texts.length === 0) {
3373
3499
  const firstDisabledOption = this.el.querySelector("option:disabled");
3374
3500
  if (firstDisabledOption && firstDisabledOption.value === "") {
3375
- this.input.value = firstDisabledOption.innerText;
3501
+ this.input.value = firstDisabledOption.textContent;
3376
3502
  return;
3377
3503
  }
3378
3504
  }
@@ -3394,7 +3520,7 @@ var FormSelect = class _FormSelect extends Component {
3394
3520
  _activateOption(ul, li) {
3395
3521
  if (!li) return;
3396
3522
  if (!this.isMultiple)
3397
- ul.querySelectorAll("li.selected").forEach((li2) => li2.classList.remove("selected"));
3523
+ ul.querySelectorAll("li.selected").forEach((row) => row.classList.remove("selected"));
3398
3524
  li.classList.add("selected");
3399
3525
  li.ariaSelected = "true";
3400
3526
  }
@@ -3680,7 +3806,6 @@ var _Datepicker = class _Datepicker extends Component {
3680
3806
  }
3681
3807
  }
3682
3808
  };
3683
- // Set input value to the selected date and close Datepicker
3684
3809
  this._finishSelection = () => {
3685
3810
  this.setInputValues();
3686
3811
  };
@@ -4236,7 +4361,7 @@ var _Datepicker = class _Datepicker extends Component {
4236
4361
  if (opts.yearRangeReverse) arr.reverse();
4237
4362
  const yearHtml = `<select class="datepicker-select orig-select-year" tabindex="-1">${arr.join("")}</select>`;
4238
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>';
4239
- 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>`;
4240
4365
  html += '<div class="selects-container">';
4241
4366
  if (opts.showMonthAfterYear) {
4242
4367
  html += yearHtml + monthHtml;
@@ -4245,7 +4370,7 @@ var _Datepicker = class _Datepicker extends Component {
4245
4370
  }
4246
4371
  html += "</div>";
4247
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>';
4248
- 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>`;
4249
4374
  return html += "</div>";
4250
4375
  }
4251
4376
  /**
@@ -4443,17 +4568,6 @@ var _Datepicker = class _Datepicker extends Component {
4443
4568
  this.el.parentElement.appendChild(dateInput);
4444
4569
  return dateInput;
4445
4570
  }
4446
- // deprecated
4447
- open() {
4448
- console.warn("Datepicker.open() is deprecated. Remove this method and wrap in modal yourself.");
4449
- return this;
4450
- }
4451
- close() {
4452
- console.warn(
4453
- "Datepicker.close() is deprecated. Remove this method and wrap in modal yourself."
4454
- );
4455
- return this;
4456
- }
4457
4571
  };
4458
4572
  _Datepicker._template = `
4459
4573
  <div class="datepicker-container">
@@ -4463,13 +4577,7 @@ _Datepicker._template = `
4463
4577
  </div>
4464
4578
  <div class="datepicker-calendar-container">
4465
4579
  <div class="datepicker-calendar"></div>
4466
- <div class="datepicker-footer">
4467
- <!--<button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>
4468
- <div class="confirmation-btns">
4469
- <button class="btn-flat datepicker-cancel waves-effect" type="button"></button>
4470
- <button class="btn-flat datepicker-done waves-effect" type="button"></button>
4471
- </div>-->
4472
- </div>
4580
+ <div class="datepicker-footer"></div>
4473
4581
  </div>
4474
4582
  </div>`;
4475
4583
  var Datepicker = _Datepicker;
@@ -4758,122 +4866,23 @@ var Lightbox = class _Lightbox extends Component {
4758
4866
  }
4759
4867
  };
4760
4868
 
4761
- // src/ts/components/modal.ts
4762
- var _defaults14 = {
4763
- opacity: 0.5,
4764
- inDuration: 250,
4765
- outDuration: 250,
4766
- onOpenStart: null,
4767
- onOpenEnd: null,
4768
- onCloseStart: null,
4769
- onCloseEnd: null,
4770
- preventScrolling: true,
4771
- dismissible: true,
4772
- startingTop: "4%",
4773
- endingTop: "10%"
4774
- };
4775
- var _Modal_static, createHtml_fn, createHtmlElement_fn;
4776
- var _Modal = class _Modal extends Component {
4777
- constructor(el, options) {
4778
- super(el, options, _Modal);
4779
- this.el["Expressive_Modal"] = this;
4780
- this.options = {
4781
- ..._Modal.defaults,
4782
- ...options
4783
- };
4784
- this.el.tabIndex = 0;
4785
- this._setupEventHandlers();
4786
- }
4787
- static get defaults() {
4788
- return _defaults14;
4789
- }
4790
- static init(els, options = {}) {
4791
- return super.init(els, options, _Modal);
4792
- }
4793
- static getInstance(el) {
4794
- return el["Expressive_Modal"];
4795
- }
4796
- destroy() {
4797
- }
4798
- _setupEventHandlers() {
4799
- }
4800
- _removeEventHandlers() {
4801
- }
4802
- _handleTriggerClick() {
4803
- }
4804
- _handleOverlayClick() {
4805
- }
4806
- _handleModalCloseClick() {
4807
- }
4808
- _handleKeydown() {
4809
- }
4810
- _handleFocus() {
4811
- }
4812
- open() {
4813
- return this;
4814
- }
4815
- close() {
4816
- return this;
4817
- }
4818
- static create(config) {
4819
- const isServer = false;
4820
- if (isServer) return __privateMethod(this, _Modal_static, createHtml_fn).call(this, config);
4821
- return __privateMethod(this, _Modal_static, createHtmlElement_fn).call(this, config);
4822
- }
4823
- };
4824
- _Modal_static = new WeakSet();
4825
- createHtml_fn = function(config) {
4826
- const title = config.header ? `<h2>${typeof config.header === "string" ? config.header : ""}</h2>` : "";
4827
- const actions = config.footer ? `<form method="dialog">${typeof config.footer === "string" ? config.footer : ""}</form>` : "";
4828
- return `<dialog id="${config.id}">
4829
- ${title}
4830
- <div>${typeof config.content === "string" ? config.content : ""}</div>
4831
- ${actions}
4832
- </dialog>`;
4833
- };
4834
- createHtmlElement_fn = function(config) {
4835
- const dialog = document.createElement("dialog");
4836
- dialog.id = config.id;
4837
- return dialog;
4838
- };
4839
- __privateAdd(_Modal, _Modal_static);
4840
- var Modal = _Modal;
4841
-
4842
4869
  // src/ts/components/parallax.ts
4843
- var _defaults15 = {
4844
- responsiveThreshold: 0
4845
- // breakpoint for swipeable
4846
- };
4847
- var _Parallax = class _Parallax extends Component {
4870
+ var _defaults14 = {};
4871
+ var Parallax = class _Parallax extends Component {
4848
4872
  constructor(el, options) {
4849
4873
  super(el, options, _Parallax);
4850
- this._handleImageLoad = () => {
4851
- this._updateParallax();
4852
- };
4853
4874
  this.el["Expressive_Parallax"] = this;
4854
4875
  this.options = {
4855
4876
  ..._Parallax.defaults,
4856
4877
  ...options
4857
4878
  };
4858
- this._enabled = window.innerWidth > this.options.responsiveThreshold;
4859
- this._img = this.el.querySelector("img");
4860
- if (!this._img) {
4861
- console.error("Parallax: no <img> to move inside the .parallax element");
4862
- return;
4879
+ if (!this.el.querySelector("img, video")) {
4880
+ console.error("Parallax: no <img> or <video> to move inside the .parallax element");
4863
4881
  }
4864
- this._updateParallax();
4865
- this._setupEventHandlers();
4866
- this._setupStyles();
4867
- _Parallax._parallaxes.push(this);
4868
4882
  }
4869
4883
  static get defaults() {
4870
- return _defaults15;
4884
+ return _defaults14;
4871
4885
  }
4872
- /**
4873
- * Initializes instances of Parallax.
4874
- * @param els HTML elements.
4875
- * @param options Component options.
4876
- */
4877
4886
  static init(els, options = {}) {
4878
4887
  return super.init(els, options, _Parallax);
4879
4888
  }
@@ -4881,87 +4890,12 @@ var _Parallax = class _Parallax extends Component {
4881
4890
  return el["Expressive_Parallax"];
4882
4891
  }
4883
4892
  destroy() {
4884
- const index = _Parallax._parallaxes.indexOf(this);
4885
- if (index >= 0) _Parallax._parallaxes.splice(index, 1);
4886
- if (this._img) this._img.style.transform = "";
4887
- this._removeEventHandlers();
4888
4893
  this.el["Expressive_Parallax"] = void 0;
4889
4894
  }
4890
- static _handleScroll() {
4891
- for (let i = 0; i < _Parallax._parallaxes.length; i++) {
4892
- const parallaxInstance = _Parallax._parallaxes[i];
4893
- parallaxInstance._updateParallax.call(parallaxInstance);
4894
- }
4895
- }
4896
- static _handleWindowResize() {
4897
- for (let i = 0; i < _Parallax._parallaxes.length; i++) {
4898
- const parallaxInstance = _Parallax._parallaxes[i];
4899
- parallaxInstance._enabled = window.innerWidth > parallaxInstance.options.responsiveThreshold;
4900
- }
4901
- }
4902
- _setupEventHandlers() {
4903
- this._img?.addEventListener("load", this._handleImageLoad);
4904
- if (_Parallax._parallaxes.length === 0) {
4905
- if (!_Parallax._handleWindowResizeThrottled) {
4906
- _Parallax._handleWindowResizeThrottled = Utils.throttle(_Parallax._handleWindowResize, 100);
4907
- }
4908
- window.addEventListener("scroll", _Parallax._requestScrollUpdate, { passive: true });
4909
- window.addEventListener("resize", _Parallax._handleWindowResizeThrottled, { passive: true });
4910
- }
4911
- }
4912
- _removeEventHandlers() {
4913
- this._img?.removeEventListener("load", this._handleImageLoad);
4914
- if (_Parallax._parallaxes.length === 0) {
4915
- window.removeEventListener("scroll", _Parallax._requestScrollUpdate);
4916
- window.removeEventListener("resize", _Parallax._handleWindowResizeThrottled);
4917
- if (_Parallax._scrollFrame !== null) {
4918
- cancelAnimationFrame(_Parallax._scrollFrame);
4919
- _Parallax._scrollFrame = null;
4920
- }
4921
- }
4922
- }
4923
- _setupStyles() {
4924
- if (this._img) this._img.style.opacity = "1";
4925
- }
4926
- _updateParallax() {
4927
- const rect = this.el.getBoundingClientRect();
4928
- const containerHeight = rect.height > 0 ? this.el.parentElement.offsetHeight : 500;
4929
- const imgHeight = this._img.offsetHeight;
4930
- const parallaxDist = imgHeight - containerHeight;
4931
- const top = rect.top + window.scrollY - document.documentElement.clientTop;
4932
- const bottom = top + containerHeight;
4933
- const scrollTop = Utils.getDocumentScrollTop();
4934
- const windowHeight = window.innerHeight;
4935
- const windowBottom = scrollTop + windowHeight;
4936
- const percentScrolled = (windowBottom - top) / (containerHeight + windowHeight);
4937
- const parallax = parallaxDist * percentScrolled;
4938
- if (!this._enabled) {
4939
- this._img.style.transform = "";
4940
- } else if (bottom > scrollTop && top < scrollTop + windowHeight) {
4941
- this._img.style.transform = `translate3D(-50%, ${parallax}px, 0)`;
4942
- }
4943
- }
4944
4895
  };
4945
- _Parallax._parallaxes = [];
4946
- _Parallax._scrollFrame = null;
4947
- /**
4948
- * Coalesce scroll events onto animation frames.
4949
- *
4950
- * The handler reads layout and then writes a transform, so running it more
4951
- * than once per frame is wasted work - and the 5ms throttle it replaces was
4952
- * short enough to let several run per frame anyway.
4953
- */
4954
- _Parallax._requestScrollUpdate = () => {
4955
- if (_Parallax._scrollFrame !== null) return;
4956
- _Parallax._scrollFrame = requestAnimationFrame(() => {
4957
- _Parallax._scrollFrame = null;
4958
- _Parallax._handleScroll();
4959
- });
4960
- };
4961
- var Parallax = _Parallax;
4962
4896
 
4963
4897
  // src/ts/components/pushpin.ts
4964
- var _defaults16 = {
4898
+ var _defaults15 = {
4965
4899
  top: 0,
4966
4900
  bottom: Infinity,
4967
4901
  offset: 0,
@@ -4981,7 +4915,7 @@ var _Pushpin = class _Pushpin extends Component {
4981
4915
  this._updatePosition();
4982
4916
  }
4983
4917
  static get defaults() {
4984
- return _defaults16;
4918
+ return _defaults15;
4985
4919
  }
4986
4920
  /**
4987
4921
  * Initializes instances of Pushpin.
@@ -5050,16 +4984,12 @@ _Pushpin._pushpins = [];
5050
4984
  var Pushpin = _Pushpin;
5051
4985
 
5052
4986
  // src/ts/components/scrollspy.ts
5053
- var _defaults17 = {
5054
- throttle: 100,
4987
+ var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
4988
+ var _defaults16 = {
5055
4989
  scrollOffset: 200,
5056
- // offset - 200 allows elements near bottom of page to scroll
5057
4990
  activeClass: "active",
5058
- getActiveElement: (id) => {
5059
- return 'a[href="#' + id + '"]';
5060
- },
5061
- keepTopElementActive: false,
5062
- animationDuration: null
4991
+ getActiveElement: _defaultGetActiveElement,
4992
+ keepTopElementActive: false
5063
4993
  };
5064
4994
  var _ScrollSpy = class _ScrollSpy extends Component {
5065
4995
  constructor(el, options) {
@@ -5069,22 +4999,17 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5069
4999
  ..._ScrollSpy.defaults,
5070
5000
  ...options
5071
5001
  };
5002
+ this.el.style.setProperty(
5003
+ "--md-comp-scrollspy-offset",
5004
+ `${this.options.scrollOffset}px`
5005
+ );
5072
5006
  _ScrollSpy._elements.push(this);
5073
- _ScrollSpy._count++;
5074
- _ScrollSpy._increment++;
5075
- this.tickId = -1;
5076
- this.id = _ScrollSpy._increment.toString();
5077
- this._setupEventHandlers();
5078
- _ScrollSpy._handleWindowScroll();
5007
+ _ScrollSpy._ensureObserver(this.options.scrollOffset);
5008
+ _ScrollSpy._observer?.observe(this.el);
5079
5009
  }
5080
5010
  static get defaults() {
5081
- return _defaults17;
5011
+ return _defaults16;
5082
5012
  }
5083
- /**
5084
- * Initializes instances of ScrollSpy.
5085
- * @param els HTML elements.
5086
- * @param options Component options.
5087
- */
5088
5013
  static init(els, options = {}) {
5089
5014
  return super.init(els, options, _ScrollSpy);
5090
5015
  }
@@ -5092,348 +5017,233 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5092
5017
  return el["Expressive_ScrollSpy"];
5093
5018
  }
5094
5019
  destroy() {
5095
- const elementIndex = _ScrollSpy._elements.indexOf(this);
5096
- if (elementIndex >= 0) _ScrollSpy._elements.splice(elementIndex, 1);
5097
- const inViewIndex = _ScrollSpy._elementsInView.indexOf(this);
5098
- if (inViewIndex >= 0) _ScrollSpy._elementsInView.splice(inViewIndex, 1);
5099
- const visibleIndex = _ScrollSpy._visibleElements.indexOf(this.el);
5100
- if (visibleIndex >= 0) _ScrollSpy._visibleElements.splice(visibleIndex, 1);
5101
- _ScrollSpy._count--;
5102
- this._removeEventHandlers();
5103
- const actElem = document.querySelector(this.options.getActiveElement(this.el.id));
5104
- actElem?.classList.remove(this.options.activeClass);
5105
- this.el["Expressive_ScrollSpy"] = void 0;
5106
- }
5107
- _setupEventHandlers() {
5108
- if (_ScrollSpy._count === 1) {
5109
- _ScrollSpy._throttledScroll = Utils.throttle(_ScrollSpy._handleWindowScroll, this.options.throttle);
5110
- _ScrollSpy._throttledResize = Utils.throttle(_ScrollSpy._handleWindowScroll, 200);
5111
- window.addEventListener("scroll", _ScrollSpy._throttledScroll, { passive: true });
5112
- window.addEventListener("resize", _ScrollSpy._throttledResize, { passive: true });
5113
- document.body.addEventListener("click", _ScrollSpy._handleTriggerClick);
5114
- }
5115
- }
5116
- _removeEventHandlers() {
5117
- if (_ScrollSpy._count === 0) {
5118
- window.removeEventListener("scroll", _ScrollSpy._throttledScroll);
5119
- window.removeEventListener("resize", _ScrollSpy._throttledResize);
5120
- document.body.removeEventListener("click", _ScrollSpy._handleTriggerClick);
5121
- _ScrollSpy._throttledScroll = null;
5122
- _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();
5123
5038
  }
5039
+ this.el["Expressive_ScrollSpy"] = void 0;
5124
5040
  }
5125
- static _findElements(top, right, bottom, left) {
5126
- const hits = [];
5127
- const docElem = document.documentElement;
5128
- const clientTop = docElem.clientTop;
5129
- const clientLeft = docElem.clientLeft;
5130
- const scrollY = window.scrollY;
5131
- const scrollX = window.scrollX;
5132
- for (let i = 0; i < _ScrollSpy._elements.length; i++) {
5133
- const scrollspy = _ScrollSpy._elements[i];
5134
- const currTop = top + scrollspy.options.scrollOffset || 200;
5135
- const box = scrollspy.el.getBoundingClientRect();
5136
- if (box.height > 0) {
5137
- const elTop = box.top + scrollY - clientTop, elLeft = box.left + scrollX - clientLeft, elRight = elLeft + box.width, elBottom = elTop + box.height;
5138
- const isIntersect = !(elLeft > right || elRight < left || elTop > bottom || elBottom < currTop);
5139
- if (isIntersect) {
5140
- hits.push(scrollspy);
5141
- }
5142
- }
5143
- }
5144
- 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
+ });
5145
5048
  }
5146
- _enter() {
5147
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5148
- (value) => value.getBoundingClientRect().height !== 0
5149
- );
5150
- if (_ScrollSpy._visibleElements[0]) {
5151
- const actElem = document.querySelector(
5152
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5153
- );
5154
- actElem?.classList.remove(this.options.activeClass);
5155
- if (_ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"] && this.id < _ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"].id) {
5156
- _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];
5157
5064
  } else {
5158
- _ScrollSpy._visibleElements.push(this.el);
5065
+ _ScrollSpy._clearActive(options);
5066
+ return;
5159
5067
  }
5160
- } else {
5161
- _ScrollSpy._visibleElements.push(this.el);
5162
5068
  }
5163
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5164
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5165
- 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;
5166
5076
  }
5167
- _exit() {
5168
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5169
- (value) => value.getBoundingClientRect().height !== 0
5170
- );
5171
- if (_ScrollSpy._visibleElements[0]) {
5172
- const actElem = document.querySelector(
5173
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5174
- );
5175
- actElem?.classList.remove(this.options.activeClass);
5176
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter((x) => x.id != this.el.id);
5177
- if (_ScrollSpy._visibleElements[0]) {
5178
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5179
- document.querySelector(selector)?.classList.add(this.options.activeClass);
5180
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5181
- }
5182
- }
5183
- }
5184
- static _resetKeptTopActiveElement(activeClass) {
5185
- if (_ScrollSpy._keptTopActiveElement) {
5186
- _ScrollSpy._keptTopActiveElement.classList.remove(activeClass);
5187
- _ScrollSpy._keptTopActiveElement = null;
5188
- }
5189
- }
5190
- static _getDistanceToViewport(element) {
5191
- const rect = element.getBoundingClientRect();
5192
- const distance = rect.top;
5193
- return distance;
5194
- }
5195
- static _smoothScrollIntoView(element, duration = 300) {
5196
- const targetPosition = element.getBoundingClientRect().top + (window.scrollY || window.pageYOffset);
5197
- const startPosition = window.scrollY || window.pageYOffset;
5198
- const distance = targetPosition - startPosition;
5199
- const startTime = performance.now();
5200
- function scrollStep(currentTime) {
5201
- const elapsed = currentTime - startTime;
5202
- const progress = Math.min(elapsed / duration, 1);
5203
- const scrollY = startPosition + distance * progress;
5204
- if (progress < 1) {
5205
- window.scrollTo(0, scrollY);
5206
- requestAnimationFrame(scrollStep);
5207
- } else {
5208
- 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;
5209
5085
  }
5210
5086
  }
5211
- requestAnimationFrame(scrollStep);
5087
+ return best;
5212
5088
  }
5213
- };
5214
- _ScrollSpy._keptTopActiveElement = null;
5215
- // The document-level listeners are shared by every instance, so the
5216
- // references they are registered with have to be shared too - registering
5217
- // with one instance's bound handler and unregistering with another's is a
5218
- // silent no-op that leaves the listener attached forever.
5219
- _ScrollSpy._throttledScroll = null;
5220
- _ScrollSpy._throttledResize = null;
5221
- _ScrollSpy._handleTriggerClick = (e) => {
5222
- const trigger = e.target;
5223
- for (let i = _ScrollSpy._elements.length - 1; i >= 0; i--) {
5224
- const scrollspy = _ScrollSpy._elements[i];
5225
- const x = document.querySelector('a[href="#' + scrollspy.el.id + '"]');
5226
- if (trigger === x) {
5227
- e.preventDefault();
5228
- if (scrollspy.el["Expressive_ScrollSpy"].options.animationDuration) {
5229
- _ScrollSpy._smoothScrollIntoView(
5230
- scrollspy.el,
5231
- scrollspy.el["Expressive_ScrollSpy"].options.animationDuration
5232
- );
5233
- } else {
5234
- 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;
5235
5106
  }
5236
- break;
5237
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;
5238
5114
  }
5239
5115
  };
5240
- _ScrollSpy._handleWindowScroll = () => {
5241
- _ScrollSpy._ticks++;
5242
- const top = Utils.getDocumentScrollTop(), left = Utils.getDocumentScrollLeft(), right = left + window.innerWidth, bottom = top + window.innerHeight;
5243
- const intersections = _ScrollSpy._findElements(top, right, bottom, left);
5244
- for (let i = 0; i < intersections.length; i++) {
5245
- const scrollspy = intersections[i];
5246
- const lastTick = scrollspy.tickId;
5247
- if (lastTick < 0) {
5248
- scrollspy._enter();
5249
- }
5250
- scrollspy.tickId = _ScrollSpy._ticks;
5251
- }
5252
- for (let i = 0; i < _ScrollSpy._elementsInView.length; i++) {
5253
- const scrollspy = _ScrollSpy._elementsInView[i];
5254
- const lastTick = scrollspy.tickId;
5255
- if (lastTick >= 0 && lastTick !== _ScrollSpy._ticks) {
5256
- scrollspy._exit();
5257
- scrollspy.tickId = -1;
5258
- }
5259
- }
5260
- _ScrollSpy._elementsInView = intersections;
5261
- if (_ScrollSpy._elements.length) {
5262
- const options = _ScrollSpy._elements[0].el["Expressive_ScrollSpy"].options;
5263
- if (options.keepTopElementActive && _ScrollSpy._visibleElements.length === 0) {
5264
- _ScrollSpy._resetKeptTopActiveElement(options.activeClass);
5265
- 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);
5266
- const nearestTopElement = topElements.length ? topElements[topElements.length - 1] : _ScrollSpy._elements[0];
5267
- const actElem = document.querySelector(options.getActiveElement(nearestTopElement.el.id));
5268
- actElem?.classList.add(options.activeClass);
5269
- _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);
5270
5126
  }
5271
5127
  }
5128
+ _ScrollSpy._syncActive();
5272
5129
  };
5273
- _ScrollSpy._elements = [];
5274
- _ScrollSpy._elementsInView = [];
5275
- _ScrollSpy._visibleElements = [];
5276
- _ScrollSpy._count = 0;
5277
- _ScrollSpy._increment = 0;
5278
- _ScrollSpy._ticks = 0;
5279
5130
  var ScrollSpy = _ScrollSpy;
5280
5131
 
5281
5132
  // src/ts/components/sidenav.ts
5282
- var _defaults18 = {
5133
+ var _defaults17 = {
5283
5134
  edge: "left",
5284
5135
  draggable: true,
5285
5136
  dragTargetWidth: "10px",
5286
- inDuration: 250,
5287
- outDuration: 200,
5288
5137
  onOpenStart: null,
5289
5138
  onOpenEnd: null,
5290
5139
  onCloseStart: null,
5291
- onCloseEnd: null,
5292
- preventScrolling: true
5140
+ onCloseEnd: null
5293
5141
  };
5142
+ var LARGE_UP = "(width >= 993px)";
5294
5143
  var _Sidenav = class _Sidenav extends Component {
5295
5144
  constructor(el, options) {
5296
5145
  super(el, options, _Sidenav);
5297
- this._handleDragTargetDrag = (e) => {
5298
- if (!this._isDraggable()) return;
5299
- let totalDeltaX = this._calculateDelta(e);
5300
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5301
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5302
- if (this.options.edge === dragDirection) {
5303
- totalDeltaX = 0;
5304
- }
5305
- let transformX = totalDeltaX;
5306
- let transformPrefix = "translateX(-100%)";
5307
- if (this.options.edge === "right") {
5308
- transformPrefix = "translateX(100%)";
5309
- transformX = -transformX;
5310
- }
5311
- this.percentOpen = Math.min(1, totalDeltaX / this._width);
5312
- this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
5313
- this._overlay.style.opacity = this.percentOpen.toString();
5314
- };
5315
- this._handleDragTargetRelease = () => {
5316
- if (this.isDragged) {
5317
- if (this.percentOpen > 0.2) {
5318
- this.open();
5319
- } else {
5320
- 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 {
5321
5165
  }
5322
- this.isDragged = false;
5323
- this._verticallyScrolling = false;
5324
5166
  }
5325
- };
5326
- this._handleCloseDrag = (e) => {
5327
- if (!this.isOpen || !this._isDraggable()) return;
5328
- let totalDeltaX = this._calculateDelta(e);
5329
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5330
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5331
- if (this.options.edge !== dragDirection) {
5332
- totalDeltaX = 0;
5167
+ this._syncTriggers();
5168
+ if (typeof this.options.onOpenEnd === "function") {
5169
+ this.options.onOpenEnd.call(this, this.el);
5333
5170
  }
5334
- let transformX = -totalDeltaX;
5335
- if (this.options.edge === "right") {
5336
- 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();
5337
5183
  }
5338
- this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
5339
- this.el.style.transform = `translateX(${transformX}px)`;
5340
- this._overlay.style.opacity = this.percentOpen.toString();
5341
5184
  };
5342
- this._calculateDelta = (e) => {
5343
- if (!this.isDragged) {
5344
- 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();
5345
5194
  }
5346
- this._dragMoveUpdate(e);
5347
- return this._xPos - this._startingXpos;
5348
5195
  };
5349
- this._handleCloseRelease = () => {
5350
- if (this.isOpen && this.isDragged) {
5351
- if (this.percentOpen > 0.8) {
5352
- this._animateIn();
5353
- } else {
5354
- this.close();
5355
- }
5356
- this.isDragged = false;
5357
- this._verticallyScrolling = false;
5196
+ this._onBreakpointChange = () => {
5197
+ if (this._isCurrentlyFixed() && this.isOpen) {
5198
+ this.close();
5358
5199
  }
5359
5200
  };
5360
- // Handles closing of Sidenav when element with class .sidenav-close
5361
5201
  this._handleCloseTriggerClick = (e) => {
5362
- 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");
5363
5205
  if (closeTrigger && !this._isCurrentlyFixed()) {
5364
5206
  this.close();
5365
5207
  }
5366
5208
  };
5367
- this._handleWindowResize = () => {
5368
- if (this.lastWindowWidth !== window.innerWidth) {
5369
- if (window.innerWidth > 992) {
5370
- this.open();
5371
- } else {
5372
- this.close();
5373
- }
5374
- }
5375
- this.lastWindowWidth = window.innerWidth;
5376
- 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);
5377
5216
  };
5378
- /**
5379
- * Opens Sidenav.
5380
- */
5381
- this.open = () => {
5382
- if (this.isOpen === true) return;
5383
- this.isOpen = true;
5384
- if (typeof this.options.onOpenStart === "function") {
5385
- this.options.onOpenStart.call(this, this.el);
5386
- }
5387
- if (this._isCurrentlyFixed()) {
5388
- this.el.style.transform = "translateX(0)";
5389
- this._enableBodyScrolling();
5390
- this._overlay.style.display = "none";
5391
- } else {
5392
- if (this.options.preventScrolling) this._preventBodyScrolling();
5393
- if (!this.isDragged || this.percentOpen != 1) this._animateIn();
5394
- this._setAriaHidden();
5395
- 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();
5396
5225
  }
5226
+ this.isDragged = false;
5227
+ this._verticallyScrolling = false;
5397
5228
  };
5398
- /**
5399
- * Closes Sidenav.
5400
- */
5401
- this.close = () => {
5402
- if (this.isOpen === false) return;
5403
- this.isOpen = false;
5404
- if (typeof this.options.onCloseStart === "function") {
5405
- this.options.onCloseStart.call(this, this.el);
5406
- }
5407
- if (this._isCurrentlyFixed()) {
5408
- const transformX = this.options.edge === "left" ? "-105%" : "105%";
5409
- 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();
5410
5242
  } else {
5411
- this._enableBodyScrolling();
5412
- if (!this.isDragged || this.percentOpen != 0) {
5413
- this._animateOut();
5414
- } else {
5415
- this._overlay.style.display = "none";
5416
- }
5417
- this._setAriaHidden();
5418
- this._setTabIndex();
5243
+ this.close();
5419
5244
  }
5420
- };
5421
- this._setAriaHidden = () => {
5422
- this.el.ariaHidden = this.isOpen ? "false" : "true";
5423
- const navWrapper = document.querySelector(".nav-wrapper ul");
5424
- if (navWrapper) navWrapper.ariaHidden = this.isOpen.toString();
5425
- };
5426
- this._setTabIndex = () => {
5427
- const navLinks = document.querySelectorAll(".nav-wrapper ul li a");
5428
- const sideNavLinks = document.querySelectorAll(".sidenav li a");
5429
- if (navLinks)
5430
- navLinks.forEach((navLink) => {
5431
- navLink.tabIndex = this.isOpen ? -1 : 0;
5432
- });
5433
- if (sideNavLinks)
5434
- sideNavLinks.forEach((sideNavLink) => {
5435
- sideNavLink.tabIndex = this.isOpen ? 0 : -1;
5436
- });
5245
+ this.isDragged = false;
5246
+ this._verticallyScrolling = false;
5437
5247
  };
5438
5248
  this.el["Expressive_Sidenav"] = this;
5439
5249
  this.options = {
@@ -5444,17 +5254,26 @@ var _Sidenav = class _Sidenav extends Component {
5444
5254
  this.isOpen = false;
5445
5255
  this.isFixed = this.el.classList.contains("sidenav-fixed");
5446
5256
  this.isDragged = false;
5447
- this.lastWindowWidth = window.innerWidth;
5448
- this.lastWindowHeight = window.innerHeight;
5449
- 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();
5450
5269
  this._createDragTarget();
5451
- this._setupEventHandlers();
5452
5270
  this._setupClasses();
5453
- this._setupFixed();
5271
+ this._setupEventHandlers();
5272
+ this._syncTriggers();
5454
5273
  _Sidenav._sidenavs.push(this);
5455
5274
  }
5456
5275
  static get defaults() {
5457
- return _defaults18;
5276
+ return _defaults17;
5458
5277
  }
5459
5278
  /**
5460
5279
  * Initializes instances of Sidenav.
@@ -5469,182 +5288,178 @@ var _Sidenav = class _Sidenav extends Component {
5469
5288
  }
5470
5289
  destroy() {
5471
5290
  this._removeEventHandlers();
5472
- this._enableBodyScrolling();
5473
- this._overlay.parentNode.removeChild(this._overlay);
5474
- 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();
5475
5300
  this.el["Expressive_Sidenav"] = void 0;
5476
- this.el.style.transform = "";
5477
5301
  const index = _Sidenav._sidenavs.indexOf(this);
5478
5302
  if (index >= 0) {
5479
5303
  _Sidenav._sidenavs.splice(index, 1);
5480
5304
  }
5481
5305
  }
5482
- _createOverlay() {
5483
- this._overlay = document.createElement("div");
5484
- this._overlay.classList.add("sidenav-overlay");
5485
- this._overlay.addEventListener("click", this.close);
5486
- 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
+ }
5487
5364
  }
5488
5365
  _setupEventHandlers() {
5489
5366
  if (_Sidenav._sidenavs.length === 0) {
5490
- document.body.addEventListener("click", this._handleTriggerClick);
5367
+ document.body.addEventListener("click", _Sidenav._handleTriggerClick);
5491
5368
  }
5492
5369
  const passive = { passive: true };
5493
- this.dragTarget.addEventListener("touchmove", this._handleDragTargetDrag, passive);
5494
- this.dragTarget.addEventListener("touchend", this._handleDragTargetRelease);
5495
- this._overlay.addEventListener("touchmove", this._handleCloseDrag, passive);
5496
- this._overlay.addEventListener("touchend", this._handleCloseRelease);
5497
- this.el.addEventListener("touchmove", this._handleCloseDrag, passive);
5498
- 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);
5499
5375
  this.el.addEventListener("click", this._handleCloseTriggerClick);
5500
- if (this.isFixed) {
5501
- window.addEventListener("resize", this._handleWindowResize, passive);
5502
- }
5503
- this._setAriaHidden();
5504
- this._setTabIndex();
5376
+ this._mql.addEventListener("change", this._onBreakpointChange);
5505
5377
  }
5506
5378
  _removeEventHandlers() {
5507
5379
  if (_Sidenav._sidenavs.length === 1) {
5508
- document.body.removeEventListener("click", this._handleTriggerClick);
5509
- }
5510
- this.dragTarget.removeEventListener("touchmove", this._handleDragTargetDrag);
5511
- this.dragTarget.removeEventListener("touchend", this._handleDragTargetRelease);
5512
- this._overlay.removeEventListener("touchmove", this._handleCloseDrag);
5513
- this._overlay.removeEventListener("touchend", this._handleCloseRelease);
5514
- this.el.removeEventListener("touchmove", this._handleCloseDrag);
5515
- this.el.removeEventListener("touchend", this._handleCloseRelease);
5516
- this.el.removeEventListener("click", this._handleCloseTriggerClick);
5517
- if (this.isFixed) {
5518
- window.removeEventListener("resize", this._handleWindowResize);
5380
+ document.body.removeEventListener("click", _Sidenav._handleTriggerClick);
5519
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);
5520
5389
  }
5521
- _handleTriggerClick(e) {
5522
- const trigger = e.target.closest(".sidenav-trigger");
5523
- if (e.target && trigger) {
5524
- const sidenavId = Utils.getIdFromTrigger(trigger);
5525
- const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5526
- if (sidenavInstance) {
5527
- sidenavInstance.open();
5528
- }
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();
5529
5399
  e.preventDefault();
5530
5400
  }
5531
5401
  }
5532
- // 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
+ }
5533
5408
  _startDrag(e) {
5534
5409
  const clientX = e.targetTouches[0].clientX;
5535
5410
  this.isDragged = true;
5536
5411
  this._startingXpos = clientX;
5537
- this._xPos = this._startingXpos;
5538
- this._time = Date.now();
5539
- this._width = this.el.getBoundingClientRect().width;
5540
- this._overlay.style.display = "block";
5412
+ this._xPos = clientX;
5413
+ this._width = this._dialog?.getBoundingClientRect().width || this.el.getBoundingClientRect().width;
5541
5414
  this._initialScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5542
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
+ }
5543
5423
  }
5544
- //Set variables needed at each drag move update tick
5545
5424
  _dragMoveUpdate(e) {
5546
5425
  const clientX = e.targetTouches[0].clientX;
5547
5426
  const currentScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5548
- this.deltaX = Math.abs(this._xPos - clientX);
5549
5427
  this._xPos = clientX;
5550
- this.velocityX = this.deltaX / (Date.now() - this._time);
5551
- this._time = Date.now();
5552
5428
  if (this._initialScrollTop !== currentScrollTop) {
5553
5429
  this._verticallyScrolling = true;
5554
5430
  }
5555
5431
  }
5556
- _setupClasses() {
5557
- if (this.options.edge === "right") {
5558
- this.el.classList.add("right-aligned");
5559
- this.dragTarget.classList.add("right-aligned");
5560
- }
5561
- }
5562
- _removeClasses() {
5563
- this.el.classList.remove("right-aligned");
5564
- this.dragTarget.classList.remove("right-aligned");
5565
- }
5566
- _setupFixed() {
5567
- if (this._isCurrentlyFixed()) this.open();
5568
- }
5569
- _isDraggable() {
5570
- return this.options.draggable && !this._isCurrentlyFixed() && !this._verticallyScrolling;
5571
- }
5572
- _isCurrentlyFixed() {
5573
- return this.isFixed && window.innerWidth > 992;
5574
- }
5575
- _createDragTarget() {
5576
- const dragTarget = document.createElement("div");
5577
- dragTarget.classList.add("drag-target");
5578
- dragTarget.style.width = this.options.dragTargetWidth;
5579
- document.body.appendChild(dragTarget);
5580
- this.dragTarget = dragTarget;
5581
- }
5582
- _preventBodyScrolling() {
5583
- document.body.style.overflow = "hidden";
5584
- }
5585
- _enableBodyScrolling() {
5586
- document.body.style.overflow = "";
5587
- }
5588
- _animateIn() {
5589
- this._animateSidenavIn();
5590
- this._animateOverlayIn();
5591
- }
5592
- _animateOut() {
5593
- this._animateSidenavOut();
5594
- this._animateOverlayOut();
5595
- }
5596
- _animateSidenavIn() {
5597
- let slideOutPercent = this.options.edge === "left" ? -1 : 1;
5598
- if (this.isDragged) {
5599
- slideOutPercent = this.options.edge === "left" ? slideOutPercent + this.percentOpen : slideOutPercent - this.percentOpen;
5600
- }
5601
- const duration = this.options.inDuration;
5602
- this.el.style.transition = "none";
5603
- this.el.style.transform = "translateX(" + slideOutPercent * 100 + "%)";
5604
- setTimeout(() => {
5605
- this.el.style.transition = `transform ${duration}ms ease`;
5606
- this.el.style.transform = "translateX(0)";
5607
- }, 1);
5608
- setTimeout(() => {
5609
- if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
5610
- }, duration);
5611
- }
5612
- _animateSidenavOut() {
5613
- const endPercent = this.options.edge === "left" ? -1 : 1;
5614
- const duration = this.options.outDuration;
5615
- this.el.style.transition = `transform ${duration}ms ease`;
5616
- this.el.style.transform = "translateX(" + endPercent * 100 + "%)";
5617
- setTimeout(() => {
5618
- if (typeof this.options.onCloseEnd === "function")
5619
- this.options.onCloseEnd.call(this, this.el);
5620
- }, duration);
5621
- }
5622
- _animateOverlayIn() {
5623
- let start = 0;
5624
- if (this.isDragged) start = this.percentOpen;
5625
- else this._overlay.style.display = "block";
5626
- const duration = this.options.inDuration;
5627
- this._overlay.style.transition = "none";
5628
- this._overlay.style.opacity = start.toString();
5629
- setTimeout(() => {
5630
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5631
- this._overlay.style.opacity = "1";
5632
- }, 1);
5633
- }
5634
- _animateOverlayOut() {
5635
- const duration = this.options.outDuration;
5636
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5637
- this._overlay.style.opacity = "0";
5638
- setTimeout(() => {
5639
- this._overlay.style.display = "none";
5640
- }, 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
+ });
5641
5456
  }
5642
5457
  };
5643
5458
  _Sidenav._sidenavs = [];
5644
5459
  var Sidenav = _Sidenav;
5645
5460
 
5646
5461
  // src/ts/components/slider.ts
5647
- var _defaults19 = {
5462
+ var _defaults18 = {
5648
5463
  indicators: true,
5649
5464
  height: 400,
5650
5465
  duration: 500,
@@ -5792,7 +5607,7 @@ var Slider = class _Slider extends Component {
5792
5607
  this.start();
5793
5608
  }
5794
5609
  static get defaults() {
5795
- return _defaults19;
5610
+ return _defaults18;
5796
5611
  }
5797
5612
  /**
5798
5613
  * Initializes instances of Slider.
@@ -5945,7 +5760,7 @@ var Slider = class _Slider extends Component {
5945
5760
  };
5946
5761
 
5947
5762
  // src/ts/components/tabs.ts
5948
- var _defaults20 = {
5763
+ var _defaults19 = {
5949
5764
  duration: 300,
5950
5765
  onShow: null,
5951
5766
  swipeable: false,
@@ -6023,7 +5838,7 @@ var Tabs = class _Tabs extends Component {
6023
5838
  this._setupEventHandlers();
6024
5839
  }
6025
5840
  static get defaults() {
6026
- return _defaults20;
5841
+ return _defaults19;
6027
5842
  }
6028
5843
  /**
6029
5844
  * Initializes instances of Tabs.
@@ -6062,7 +5877,7 @@ var Tabs = class _Tabs extends Component {
6062
5877
  }
6063
5878
  _queryTabLinks() {
6064
5879
  return this.el.querySelectorAll(
6065
- ":scope > a, :scope > .tab > a, :scope > li.tab > a"
5880
+ ":scope > a, :scope > .tab > a"
6066
5881
  );
6067
5882
  }
6068
5883
  _createIndicator() {
@@ -6104,7 +5919,7 @@ var Tabs = class _Tabs extends Component {
6104
5919
  }
6105
5920
  });
6106
5921
  const tabsWrapper = document.createElement("div");
6107
- tabsWrapper.classList.add("tabs-content", "carousel", "carousel-slider");
5922
+ tabsWrapper.classList.add("tabs-content", "carousel", "flat");
6108
5923
  tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]);
6109
5924
  tabsContent.forEach((tabContent) => {
6110
5925
  tabsWrapper.appendChild(tabContent);
@@ -6191,67 +6006,103 @@ var Tabs = class _Tabs extends Component {
6191
6006
  };
6192
6007
 
6193
6008
  // src/ts/components/tapTarget.ts
6194
- var _defaults21 = {
6009
+ var _defaults20 = {
6195
6010
  onOpen: null,
6196
6011
  onClose: null
6197
6012
  };
6198
6013
  var _TapTarget = class _TapTarget extends Component {
6199
6014
  constructor(el, options) {
6200
6015
  super(el, options, _TapTarget);
6201
- // Built once per instance; see the note in carousel.ts - the previous form
6202
- // returned a new throttled function on every resize and never invoked it.
6203
- this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
6204
- this._handleKeyboardInteraction = (e) => {
6205
- if (Utils.keys.ENTER.includes(e.key)) {
6206
- this._handleTargetToggle();
6207
- }
6208
- };
6209
- this._handleTargetToggle = () => {
6210
- if (!this.isOpen) this.open();
6211
- else this.close();
6212
- };
6213
- /*_handleOriginClick = () => {
6214
- this.close();
6215
- }*/
6216
- this._handleResize = () => {
6217
- this._calculatePositioning();
6218
- };
6219
- this._handleDocumentClick = (e) => {
6220
- const target = e.target;
6221
- if (!(target instanceof Element)) return;
6222
- if (!this.originEl.contains(target) && !target.closest(".tap-target-wrapper")) {
6223
- this.close();
6224
- }
6225
- };
6016
+ this.wrapper = null;
6017
+ this.waveEl = null;
6018
+ this.contentEl = null;
6019
+ this._createdWrapper = false;
6020
+ this._createdWave = false;
6021
+ this._usePopover = false;
6022
+ this._liftedStatic = false;
6023
+ this._opening = false;
6226
6024
  /**
6227
6025
  * Open Tap Target.
6228
6026
  */
6229
6027
  this.open = () => {
6230
- if (this.isOpen) return;
6028
+ if (this.isOpen || !this.originEl || !this.wrapper) return;
6029
+ _TapTarget._taptargets.forEach((other) => {
6030
+ if (other !== this) other.close();
6031
+ });
6032
+ this._calculatePositioning();
6231
6033
  if (typeof this.options.onOpen === "function") {
6232
6034
  this.options.onOpen.call(this, this.originEl);
6233
6035
  }
6234
6036
  this.isOpen = true;
6235
6037
  this.wrapper.classList.add("open");
6236
- this.wrapper.ariaExpanded = "true";
6237
- document.body.addEventListener("click", this._handleDocumentClick, true);
6238
- document.body.addEventListener("keypress", this._handleDocumentClick, true);
6239
- document.body.addEventListener("touchend", this._handleDocumentClick);
6038
+ this.originEl.setAttribute("aria-expanded", "true");
6039
+ if (!this._usePopover) {
6040
+ this.originEl.classList.add("tap-target-origin");
6041
+ if (getComputedStyle(this.originEl).position === "static") {
6042
+ this.originEl.style.position = "relative";
6043
+ this._liftedStatic = true;
6044
+ }
6045
+ }
6046
+ if (this._usePopover) {
6047
+ this._opening = true;
6048
+ try {
6049
+ this.wrapper.showPopover();
6050
+ } catch {
6051
+ }
6052
+ requestAnimationFrame(() => {
6053
+ this._opening = false;
6054
+ });
6055
+ }
6240
6056
  };
6241
6057
  /**
6242
6058
  * Close Tap Target.
6243
6059
  */
6244
6060
  this.close = () => {
6245
6061
  if (!this.isOpen) return;
6246
- if (typeof this.options.onClose === "function") {
6062
+ if (typeof this.options.onClose === "function" && this.originEl) {
6247
6063
  this.options.onClose.call(this, this.originEl);
6248
6064
  }
6249
6065
  this.isOpen = false;
6250
- this.wrapper.classList.remove("open");
6251
- this.wrapper.ariaExpanded = "false";
6252
- document.body.removeEventListener("click", this._handleDocumentClick, true);
6253
- document.body.removeEventListener("keypress", this._handleDocumentClick, true);
6254
- document.body.removeEventListener("touchend", this._handleDocumentClick);
6066
+ this.wrapper?.classList.remove("open");
6067
+ this.originEl?.setAttribute("aria-expanded", "false");
6068
+ this.originEl?.classList.remove("tap-target-origin");
6069
+ if (this._liftedStatic && this.originEl) {
6070
+ this.originEl.style.position = "";
6071
+ this._liftedStatic = false;
6072
+ }
6073
+ if (this._usePopover && this.wrapper) {
6074
+ try {
6075
+ this.wrapper.hidePopover();
6076
+ } catch {
6077
+ }
6078
+ }
6079
+ };
6080
+ // Built once per instance; a fresh throttle per event never fires.
6081
+ this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
6082
+ this._handleOriginKeydown = (e) => {
6083
+ if (Utils.keys.ENTER.includes(e.key) || e.key === " ") {
6084
+ e.preventDefault();
6085
+ this._handleTargetToggle();
6086
+ }
6087
+ };
6088
+ this._handleTargetToggle = () => {
6089
+ if (!this.isOpen) this.open();
6090
+ else this.close();
6091
+ };
6092
+ this._handleResize = () => {
6093
+ if (this.isOpen) this._calculatePositioning();
6094
+ };
6095
+ this._handlePopoverToggle = (e) => {
6096
+ const state = "newState" in e ? String(e.newState) : "";
6097
+ if (state === "open") return;
6098
+ if (this._opening) {
6099
+ try {
6100
+ this.wrapper?.showPopover();
6101
+ } catch {
6102
+ }
6103
+ return;
6104
+ }
6105
+ if (this.isOpen) this.close();
6255
6106
  };
6256
6107
  this.el["Expressive_TapTarget"] = this;
6257
6108
  this.options = {
@@ -6264,20 +6115,14 @@ var _TapTarget = class _TapTarget extends Component {
6264
6115
  console.error(`TapTarget: no element with id "${el.dataset.target ?? ""}" to attach to`);
6265
6116
  return;
6266
6117
  }
6267
- this.originEl.tabIndex = 0;
6268
6118
  this._setup();
6269
6119
  this._calculatePositioning();
6270
6120
  this._setupEventHandlers();
6271
6121
  _TapTarget._taptargets.push(this);
6272
6122
  }
6273
6123
  static get defaults() {
6274
- return _defaults21;
6124
+ return _defaults20;
6275
6125
  }
6276
- /**
6277
- * Initializes instances of TapTarget.
6278
- * @param els HTML elements.
6279
- * @param options Component options.
6280
- */
6281
6126
  static init(els, options = {}) {
6282
6127
  return super.init(els, options, _TapTarget);
6283
6128
  }
@@ -6287,123 +6132,102 @@ var _TapTarget = class _TapTarget extends Component {
6287
6132
  destroy() {
6288
6133
  this.close();
6289
6134
  this._removeEventHandlers();
6135
+ this._teardownDom();
6290
6136
  this.el["Expressive_TapTarget"] = void 0;
6291
6137
  const index = _TapTarget._taptargets.indexOf(this);
6292
- if (index >= 0) {
6293
- _TapTarget._taptargets.splice(index, 1);
6294
- }
6295
- }
6296
- _setupEventHandlers() {
6297
- if (!this.originEl) return;
6298
- this.originEl.addEventListener("click", this._handleTargetToggle);
6299
- this.originEl.addEventListener("keypress", this._handleKeyboardInteraction, true);
6300
- window.addEventListener("resize", this._handleThrottledResize);
6301
- }
6302
- _removeEventHandlers() {
6303
- if (!this.originEl) return;
6304
- this.originEl.removeEventListener("click", this._handleTargetToggle);
6305
- this.originEl.removeEventListener("keypress", this._handleKeyboardInteraction, true);
6306
- window.removeEventListener("resize", this._handleThrottledResize);
6138
+ if (index >= 0) _TapTarget._taptargets.splice(index, 1);
6307
6139
  }
6308
6140
  _setup() {
6309
- this.wrapper = this.el.parentElement;
6310
- this.waveEl = this.wrapper.querySelector(".tap-target-wave");
6311
- this.el.parentElement.ariaExpanded = "false";
6312
- this.originEl.style.zIndex = "1002";
6313
- this.contentEl = this.el.querySelector(".tap-target-content");
6314
- if (!this.wrapper.classList.contains(".tap-target-wrapper")) {
6141
+ const parent = this.el.parentElement;
6142
+ if (parent?.classList.contains("tap-target-wrapper")) {
6143
+ this.wrapper = parent;
6144
+ } else {
6315
6145
  this.wrapper = document.createElement("div");
6316
6146
  this.wrapper.classList.add("tap-target-wrapper");
6317
6147
  this.el.before(this.wrapper);
6318
6148
  this.wrapper.append(this.el);
6149
+ this._createdWrapper = true;
6319
6150
  }
6151
+ this.contentEl = this.el.querySelector(".tap-target-content");
6320
6152
  if (!this.contentEl) {
6321
6153
  this.contentEl = document.createElement("div");
6322
- this.contentEl.classList.add("tap-target-content");
6154
+ this.contentEl.className = "tap-target-content";
6155
+ while (this.el.firstChild) this.contentEl.append(this.el.firstChild);
6323
6156
  this.el.append(this.contentEl);
6324
6157
  }
6158
+ this.waveEl = this.el.querySelector(".tap-target-wave") ?? this.wrapper.querySelector(".tap-target-wave");
6325
6159
  if (!this.waveEl) {
6326
6160
  this.waveEl = document.createElement("div");
6327
- this.waveEl.classList.add("tap-target-wave");
6328
- this.wrapper.append(this.waveEl);
6161
+ this.waveEl.className = "tap-target-wave";
6162
+ this._createdWave = true;
6163
+ }
6164
+ this.el.prepend(this.waveEl);
6165
+ this.el.setAttribute("role", "dialog");
6166
+ this._labelFromHeading();
6167
+ const origin = this.originEl;
6168
+ origin.setAttribute("aria-expanded", "false");
6169
+ origin.setAttribute("aria-controls", this.el.id || this._ensureId());
6170
+ this._usePopover = typeof this.wrapper.showPopover === "function";
6171
+ if (this._usePopover) {
6172
+ this.wrapper.setAttribute("popover", "auto");
6173
+ }
6174
+ }
6175
+ _ensureId() {
6176
+ if (!this.el.id) this.el.id = `tap-target-${Utils.guid()}`;
6177
+ return this.el.id;
6178
+ }
6179
+ _labelFromHeading() {
6180
+ const heading = this.contentEl?.querySelector("h1, h2, h3, h4, h5, h6");
6181
+ if (!heading) return;
6182
+ if (!heading.id) heading.id = `tap-target-title-${Utils.guid()}`;
6183
+ this.el.setAttribute("aria-labelledby", heading.id);
6184
+ }
6185
+ _teardownDom() {
6186
+ if (this._createdWave) this.waveEl?.remove();
6187
+ if (this._createdWrapper && this.wrapper) {
6188
+ this.wrapper.before(this.el);
6189
+ this.wrapper.remove();
6190
+ }
6191
+ this.wrapper = null;
6192
+ this.waveEl = null;
6193
+ }
6194
+ _setupEventHandlers() {
6195
+ if (!this.originEl) return;
6196
+ this.originEl.addEventListener("click", this._handleTargetToggle);
6197
+ if (!this.originEl.matches('button, a, [tabindex], [role="button"]')) {
6198
+ this.originEl.tabIndex = 0;
6199
+ this.originEl.addEventListener("keydown", this._handleOriginKeydown);
6329
6200
  }
6201
+ this.wrapper?.addEventListener("toggle", this._handlePopoverToggle);
6202
+ window.addEventListener("resize", this._handleThrottledResize, { passive: true });
6330
6203
  }
6331
- _offset(el) {
6332
- const box = el.getBoundingClientRect();
6333
- const docElem = document.documentElement;
6334
- return {
6335
- top: box.top + window.pageYOffset - docElem.clientTop,
6336
- left: box.left + window.pageXOffset - docElem.clientLeft
6337
- };
6204
+ _removeEventHandlers() {
6205
+ if (!this.originEl) return;
6206
+ this.originEl.removeEventListener("click", this._handleTargetToggle);
6207
+ this.originEl.removeEventListener("keydown", this._handleOriginKeydown);
6208
+ this.wrapper?.removeEventListener("toggle", this._handlePopoverToggle);
6209
+ window.removeEventListener("resize", this._handleThrottledResize);
6338
6210
  }
6339
6211
  _calculatePositioning() {
6340
- let isFixed = getComputedStyle(this.originEl).position === "fixed";
6341
- if (!isFixed) {
6342
- let currentElem = this.originEl;
6343
- const parents = [];
6344
- while ((currentElem = currentElem.parentNode) && currentElem !== document)
6345
- parents.push(currentElem);
6346
- for (let i = 0; i < parents.length; i++) {
6347
- isFixed = getComputedStyle(parents[i]).position === "fixed";
6348
- if (isFixed) break;
6349
- }
6350
- }
6351
- const originWidth = this.originEl.offsetWidth;
6352
- const originHeight = this.originEl.offsetHeight;
6353
- const originOffset = this._offset(this.originEl);
6354
- const originTop = isFixed ? originOffset.top - Utils.getDocumentScrollTop() : originOffset.top;
6355
- const originLeft = isFixed ? originOffset.left - Utils.getDocumentScrollLeft() : originOffset.left;
6356
- const windowWidth = window.innerWidth;
6357
- const windowHeight = window.innerHeight;
6358
- const scrollBarWidth = windowWidth - document.documentElement.clientWidth;
6359
- const centerX = windowWidth / 2;
6360
- const centerY = windowHeight / 2;
6361
- const isLeft = originLeft <= centerX;
6362
- const isRight = originLeft > centerX;
6363
- const isTop = originTop <= centerY;
6364
- const isBottom = originTop > centerY;
6365
- const isCenterX = originLeft >= windowWidth * 0.25 && originLeft <= windowWidth * 0.75;
6366
- const tapTargetWidth = this.el.offsetWidth;
6367
- const tapTargetHeight = this.el.offsetHeight;
6368
- const tapTargetTop = originTop + originHeight / 2 - tapTargetHeight / 2;
6369
- const tapTargetLeft = originLeft + originWidth / 2 - tapTargetWidth / 2;
6370
- const tapTargetPosition = isFixed ? "fixed" : "absolute";
6371
- const tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth / 2 + originWidth;
6372
- const tapTargetTextHeight = tapTargetHeight / 2;
6373
- const tapTargetTextTop = isTop ? tapTargetHeight / 2 : 0;
6374
- const tapTargetTextBottom = 0;
6375
- const tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth / 2 - originWidth : 0;
6376
- const tapTargetTextRight = 0;
6377
- const tapTargetTextPadding = originWidth;
6378
- const tapTargetTextAlign = isBottom ? "bottom" : "top";
6379
- const tapTargetWaveWidth = originWidth > originHeight ? originWidth * 2 : originWidth * 2;
6380
- const tapTargetWaveHeight = tapTargetWaveWidth;
6381
- const tapTargetWaveTop = tapTargetHeight / 2 - tapTargetWaveHeight / 2;
6382
- const tapTargetWaveLeft = tapTargetWidth / 2 - tapTargetWaveWidth / 2;
6383
- this.wrapper.style.top = isTop ? tapTargetTop + "px" : "";
6384
- this.wrapper.style.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth - scrollBarWidth + "px" : "";
6385
- this.wrapper.style.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight + "px" : "";
6386
- this.wrapper.style.left = isLeft ? tapTargetLeft + "px" : "";
6387
- this.wrapper.style.position = tapTargetPosition;
6388
- this.contentEl.style.width = tapTargetTextWidth + "px";
6389
- this.contentEl.style.height = tapTargetTextHeight + "px";
6390
- this.contentEl.style.top = tapTargetTextTop + "px";
6391
- this.contentEl.style.right = tapTargetTextRight + "px";
6392
- this.contentEl.style.bottom = tapTargetTextBottom + "px";
6393
- this.contentEl.style.left = tapTargetTextLeft + "px";
6394
- this.contentEl.style.padding = tapTargetTextPadding + "px";
6395
- this.contentEl.style.verticalAlign = tapTargetTextAlign;
6396
- this.waveEl.style.top = tapTargetWaveTop + "px";
6397
- this.waveEl.style.left = tapTargetWaveLeft + "px";
6398
- this.waveEl.style.width = tapTargetWaveWidth + "px";
6399
- this.waveEl.style.height = tapTargetWaveHeight + "px";
6212
+ if (!this.originEl || !this.wrapper) return;
6213
+ const rect = this.originEl.getBoundingClientRect();
6214
+ const x = rect.left + rect.width / 2;
6215
+ const y = rect.top + rect.height / 2;
6216
+ const size = Math.max(rect.width, rect.height, 1);
6217
+ this.wrapper.style.setProperty("--md-comp-tap-target-x", `${x}px`);
6218
+ this.wrapper.style.setProperty("--md-comp-tap-target-y", `${y}px`);
6219
+ this.wrapper.style.setProperty("--md-comp-tap-target-origin-size", `${size}px`);
6220
+ const vertical = y <= window.innerHeight / 2 ? "top" : "bottom";
6221
+ const onCenter = x >= window.innerWidth * 0.25 && x <= window.innerWidth * 0.75;
6222
+ const horizontal = onCenter ? "center" : x <= window.innerWidth / 2 ? "left" : "right";
6223
+ this.wrapper.dataset.edge = `${vertical}-${horizontal}`;
6400
6224
  }
6401
6225
  };
6402
6226
  _TapTarget._taptargets = [];
6403
6227
  var TapTarget = _TapTarget;
6404
6228
 
6405
6229
  // src/ts/components/timepicker.ts
6406
- var _defaults22 = {
6230
+ var _defaults21 = {
6407
6231
  dialRadius: 135,
6408
6232
  outerRadius: 105,
6409
6233
  innerRadius: 70,
@@ -6601,7 +6425,7 @@ var _Timepicker = class _Timepicker extends Component {
6601
6425
  }
6602
6426
  }
6603
6427
  static get defaults() {
6604
- return _defaults22;
6428
+ return _defaults21;
6605
6429
  }
6606
6430
  /**
6607
6431
  * Initializes instances of Timepicker.
@@ -6684,7 +6508,7 @@ var _Timepicker = class _Timepicker extends Component {
6684
6508
  }
6685
6509
  /*private _createButton(text: string, visibility: string): HTMLButtonElement {
6686
6510
  const button = document.createElement('button');
6687
- button.classList.add('btn', 'waves-effect', 'text');
6511
+ button.classList.add('waves-effect', 'text');
6688
6512
  button.style.visibility = visibility;
6689
6513
  button.type = 'button';
6690
6514
  button.tabIndex = -1;
@@ -6725,14 +6549,14 @@ var _Timepicker = class _Timepicker extends Component {
6725
6549
  _clockSetup() {
6726
6550
  if (this.options.twelveHour) {
6727
6551
  this._amBtn = document.createElement("div");
6728
- this._amBtn.classList.add("am-btn", "btn");
6552
+ this._amBtn.classList.add("am-btn");
6729
6553
  this._amBtn.innerText = "AM";
6730
6554
  this._amBtn.tabIndex = 0;
6731
6555
  this._amBtn.addEventListener("click", this._handleAmPmClick);
6732
6556
  this._amBtn.addEventListener("keypress", this._handleAmPmKeypress);
6733
6557
  this.spanAmPm.appendChild(this._amBtn);
6734
6558
  this._pmBtn = document.createElement("div");
6735
- this._pmBtn.classList.add("pm-btn", "btn");
6559
+ this._pmBtn.classList.add("pm-btn");
6736
6560
  this._pmBtn.innerText = "PM";
6737
6561
  this._pmBtn.tabIndex = 0;
6738
6562
  this._pmBtn.addEventListener("click", this._handleAmPmClick);
@@ -6939,19 +6763,6 @@ var _Timepicker = class _Timepicker extends Component {
6939
6763
  this.hours = (/* @__PURE__ */ new Date()).getHours();
6940
6764
  this.inputHours.value = (this.hours % (this.options.twelveHour ? 12 : 24)).toString();
6941
6765
  }
6942
- // deprecated
6943
- open() {
6944
- console.warn(
6945
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6946
- );
6947
- return this;
6948
- }
6949
- close() {
6950
- console.warn(
6951
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6952
- );
6953
- return this;
6954
- }
6955
6766
  };
6956
6767
  _Timepicker._template = `<div class="timepicker-container">
6957
6768
  <div class="timepicker-digital-display">
@@ -6984,7 +6795,7 @@ _Timepicker._template = `<div class="timepicker-container">
6984
6795
  var Timepicker = _Timepicker;
6985
6796
 
6986
6797
  // src/ts/components/toasts.ts
6987
- var _defaults23 = {
6798
+ var _defaults22 = {
6988
6799
  text: "",
6989
6800
  action: "",
6990
6801
  onAction: null,
@@ -7016,7 +6827,7 @@ var _Toast = class _Toast {
7016
6827
  this._setTimer();
7017
6828
  }
7018
6829
  static get defaults() {
7019
- return _defaults23;
6830
+ return _defaults22;
7020
6831
  }
7021
6832
  static getInstance(el) {
7022
6833
  return el["Expressive_Toast"];
@@ -7041,8 +6852,8 @@ var _Toast = class _Toast {
7041
6852
  }
7042
6853
  static _onDragStart(e) {
7043
6854
  const target = e.target;
7044
- if (target && !target.closest("button, a") && target.closest(".toast, .snackbar")) {
7045
- const toastElem = target.closest(".toast, .snackbar");
6855
+ if (target && !target.closest("button, a") && target.closest(".snackbar")) {
6856
+ const toastElem = target.closest(".snackbar");
7046
6857
  const toast = toastElem["Expressive_Toast"];
7047
6858
  if (!toast) return;
7048
6859
  toast.panning = true;
@@ -7109,7 +6920,7 @@ var _Toast = class _Toast {
7109
6920
  const node = toast.content.cloneNode(true);
7110
6921
  toast = node.firstElementChild;
7111
6922
  }
7112
- toast.classList.add("toast", "snackbar");
6923
+ toast.classList.add("snackbar");
7113
6924
  toast.setAttribute("role", "status");
7114
6925
  toast.setAttribute("aria-live", "polite");
7115
6926
  toast.setAttribute("aria-atomic", "true");
@@ -7140,7 +6951,7 @@ var _Toast = class _Toast {
7140
6951
  close.className = "circle";
7141
6952
  close.setAttribute("aria-label", "Dismiss");
7142
6953
  const icon = document.createElement("i");
7143
- icon.className = "material-icons";
6954
+ icon.className = "material-symbols";
7144
6955
  icon.setAttribute("aria-hidden", "true");
7145
6956
  icon.textContent = "close";
7146
6957
  close.appendChild(icon);
@@ -7229,7 +7040,7 @@ _Toast._draggedToast = null;
7229
7040
  var Toast = _Toast;
7230
7041
 
7231
7042
  // src/ts/components/tooltip.ts
7232
- var _defaults24 = {
7043
+ var _defaults23 = {
7233
7044
  exitDelay: 200,
7234
7045
  enterDelay: 0,
7235
7046
  text: "",
@@ -7297,7 +7108,7 @@ var Tooltip = class _Tooltip extends Component {
7297
7108
  this._setupEventHandlers();
7298
7109
  }
7299
7110
  static get defaults() {
7300
- return _defaults24;
7111
+ return _defaults23;
7301
7112
  }
7302
7113
  /**
7303
7114
  * Initializes instances of Tooltip.
@@ -7320,7 +7131,7 @@ var Tooltip = class _Tooltip extends Component {
7320
7131
  }
7321
7132
  _appendTooltipEl() {
7322
7133
  this.tooltipEl = document.createElement("div");
7323
- this.tooltipEl.classList.add("tooltip", "material-tooltip");
7134
+ this.tooltipEl.classList.add("tooltip");
7324
7135
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
7325
7136
  this.tooltipEl.setAttribute("role", "tooltip");
7326
7137
  this.el.setAttribute("aria-describedby", this.tooltipEl.id);
@@ -7481,7 +7292,6 @@ var AUTO_INIT_COMPONENTS = {
7481
7292
  Datepicker: { component: Datepicker, selector: ".datepicker" },
7482
7293
  Dropdown: { component: Dropdown, selector: ".dropdown-trigger" },
7483
7294
  Lightbox: { component: Lightbox, selector: ".lightboxed" },
7484
- Modal: { component: Modal, selector: ".modal" },
7485
7295
  Parallax: { component: Parallax, selector: ".parallax" },
7486
7296
  Pushpin: { component: Pushpin, selector: ".pushpin" },
7487
7297
  ScrollSpy: { component: ScrollSpy, selector: ".scrollspy" },
@@ -7505,7 +7315,7 @@ function AutoInit(context = document.body, options) {
7505
7315
  }
7506
7316
 
7507
7317
  // src/ts/index.ts
7508
- var version = "0.2.0";
7318
+ var version = "0.4.0";
7509
7319
  if (typeof document !== "undefined") {
7510
7320
  document.addEventListener("keydown", Utils.docHandleKeydown, true);
7511
7321
  document.addEventListener("keyup", Utils.docHandleKeyup, true);