@expressivecss/expressive 0.11.0 → 0.12.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 (140) hide show
  1. package/CHANGELOG.md +162 -7
  2. package/README.md +1 -1
  3. package/dist/css/expressive.css +230 -99
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/js/chunks/{chunk-IMUPRRI6.mjs → chunk-3VOK6J7U.mjs} +3 -3
  8. package/dist/js/chunks/{chunk-XDB3G6RL.mjs → chunk-6N2XAEFK.mjs} +15 -4
  9. package/dist/js/chunks/{chunk-XDB3G6RL.mjs.map → chunk-6N2XAEFK.mjs.map} +2 -2
  10. package/dist/js/chunks/{chunk-MISGHDUU.mjs → chunk-6OMRGML6.mjs} +9 -7
  11. package/dist/js/chunks/{chunk-MISGHDUU.mjs.map → chunk-6OMRGML6.mjs.map} +2 -2
  12. package/dist/js/chunks/{chunk-A3BJA7V4.mjs → chunk-6WLSDZ4O.mjs} +2 -2
  13. package/dist/js/chunks/{chunk-JODJAGFS.mjs → chunk-CKQP6P76.mjs} +31 -8
  14. package/dist/js/chunks/chunk-CKQP6P76.mjs.map +7 -0
  15. package/dist/js/chunks/{chunk-KR44BSYQ.mjs → chunk-DLWYKFEI.mjs} +3 -3
  16. package/dist/js/chunks/{chunk-SLFNPY5M.mjs → chunk-EC63CHXU.mjs} +2 -2
  17. package/dist/js/chunks/chunk-G3I5H2U3.mjs +7 -0
  18. package/dist/js/chunks/{chunk-PMBPAFAS.mjs.map → chunk-G3I5H2U3.mjs.map} +1 -1
  19. package/dist/js/chunks/{chunk-LZVBJ33S.mjs → chunk-GZWPXXY6.mjs} +15 -8
  20. package/dist/js/chunks/chunk-GZWPXXY6.mjs.map +7 -0
  21. package/dist/js/chunks/{chunk-74N6U5JJ.mjs → chunk-H2WA4XHH.mjs} +36 -35
  22. package/dist/js/chunks/chunk-H2WA4XHH.mjs.map +7 -0
  23. package/dist/js/chunks/{chunk-XFJ452AZ.mjs → chunk-HB6IW7QQ.mjs} +5 -6
  24. package/dist/js/chunks/{chunk-XFJ452AZ.mjs.map → chunk-HB6IW7QQ.mjs.map} +2 -2
  25. package/dist/js/chunks/{chunk-AYYYWUJ4.mjs → chunk-HLDXZ7XB.mjs} +17 -11
  26. package/dist/js/chunks/chunk-HLDXZ7XB.mjs.map +7 -0
  27. package/dist/js/chunks/{chunk-7GKXUG4B.mjs → chunk-HNFSMIBY.mjs} +18 -18
  28. package/dist/js/chunks/{chunk-D4UZ4HFN.mjs → chunk-IFXVDDDH.mjs} +23 -11
  29. package/dist/js/chunks/chunk-IFXVDDDH.mjs.map +7 -0
  30. package/dist/js/chunks/{chunk-QSQ24FYT.mjs → chunk-LTWPGFBR.mjs} +2 -2
  31. package/dist/js/chunks/{chunk-QSQ24FYT.mjs.map → chunk-LTWPGFBR.mjs.map} +2 -2
  32. package/dist/js/chunks/{chunk-I5KR22BY.mjs → chunk-LWBQIX5J.mjs} +15 -15
  33. package/dist/js/chunks/chunk-LWBQIX5J.mjs.map +7 -0
  34. package/dist/js/chunks/{chunk-GY2Z5CJ2.mjs → chunk-NNYP33NB.mjs} +67 -32
  35. package/dist/js/chunks/chunk-NNYP33NB.mjs.map +7 -0
  36. package/dist/js/chunks/{chunk-VAS6JQ6P.mjs → chunk-PIJ2TAR3.mjs} +3 -3
  37. package/dist/js/chunks/{chunk-JR24UB4X.mjs → chunk-PSSHQWCX.mjs} +2 -2
  38. package/dist/js/chunks/{chunk-PIIAEYAJ.mjs → chunk-QDAL4IYN.mjs} +2 -2
  39. package/dist/js/chunks/{chunk-FRB7TOCS.mjs → chunk-QV2JAWIZ.mjs} +2 -2
  40. package/dist/js/chunks/{chunk-N3UHGN3N.mjs → chunk-QVVEWBOF.mjs} +3 -3
  41. package/dist/js/chunks/{chunk-CDW6WIRT.mjs → chunk-RFZZCYVU.mjs} +18 -11
  42. package/dist/js/chunks/chunk-RFZZCYVU.mjs.map +7 -0
  43. package/dist/js/chunks/{chunk-TYM6U5DY.mjs → chunk-UAEAQBRC.mjs} +2 -2
  44. package/dist/js/chunks/{chunk-7UXHSYIA.mjs → chunk-UBLRRJ7N.mjs} +3 -3
  45. package/dist/js/chunks/{chunk-EP3CVKB5.mjs → chunk-UEZUJQ66.mjs} +8 -5
  46. package/dist/js/chunks/chunk-UEZUJQ66.mjs.map +7 -0
  47. package/dist/js/chunks/{chunk-JNPIWFJT.mjs → chunk-UNEMYWEW.mjs} +3 -3
  48. package/dist/js/chunks/{chunk-JKNPQQWY.mjs → chunk-WJXDBPXQ.mjs} +28 -12
  49. package/dist/js/chunks/chunk-WJXDBPXQ.mjs.map +7 -0
  50. package/dist/js/chunks/{chunk-XO5WX3TK.mjs → chunk-YDCS5S3J.mjs} +2 -2
  51. package/dist/js/chunks/{chunk-TK6PX2GC.mjs → chunk-YSBCHYXP.mjs} +16 -8
  52. package/dist/js/chunks/chunk-YSBCHYXP.mjs.map +7 -0
  53. package/dist/js/expressive.cjs +263 -133
  54. package/dist/js/expressive.cjs.map +2 -2
  55. package/dist/js/expressive.js +263 -133
  56. package/dist/js/expressive.js.map +2 -2
  57. package/dist/js/expressive.min.js +9 -9
  58. package/dist/js/expressive.min.js.map +3 -3
  59. package/dist/js/expressive.mjs +30 -30
  60. package/dist/js/internal/behaviors/bottomSheets.mjs +3 -3
  61. package/dist/js/internal/behaviors/dialogs.mjs +2 -2
  62. package/dist/js/internal/behaviors/forms.mjs +2 -2
  63. package/dist/js/internal/behaviors/sheetDrag.mjs +2 -2
  64. package/dist/js/internal/behaviors/sideSheets.mjs +3 -3
  65. package/dist/js/internal/components/appBar.mjs +2 -2
  66. package/dist/js/internal/components/autocomplete.mjs +4 -4
  67. package/dist/js/internal/components/buttonGroup.mjs +2 -2
  68. package/dist/js/internal/components/buttons.mjs +3 -3
  69. package/dist/js/internal/components/cards.mjs +3 -3
  70. package/dist/js/internal/components/carousel.mjs +3 -3
  71. package/dist/js/internal/components/characterCounter.mjs +2 -2
  72. package/dist/js/internal/components/chips.mjs +5 -5
  73. package/dist/js/internal/components/datepicker.mjs +6 -6
  74. package/dist/js/internal/components/expandingCard.mjs +3 -3
  75. package/dist/js/internal/components/index.mjs +23 -23
  76. package/dist/js/internal/components/lightbox.mjs +3 -3
  77. package/dist/js/internal/components/menu.mjs +3 -3
  78. package/dist/js/internal/components/navigationRail.mjs +2 -2
  79. package/dist/js/internal/components/registry.mjs +24 -24
  80. package/dist/js/internal/components/scrollspy.mjs +2 -2
  81. package/dist/js/internal/components/select.mjs +4 -4
  82. package/dist/js/internal/components/slider.mjs +3 -3
  83. package/dist/js/internal/components/snackbar.mjs +2 -2
  84. package/dist/js/internal/components/tabs.mjs +4 -4
  85. package/dist/js/internal/components/timepicker.mjs +4 -4
  86. package/dist/js/internal/components/tooltip.mjs +3 -3
  87. package/dist/js/internal/core/component.mjs +1 -1
  88. package/dist/js/internal/core/utils.mjs +1 -1
  89. package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
  90. package/dist/js/modular.mjs +30 -30
  91. package/dist/types/components/appBar.d.ts +1 -1
  92. package/dist/types/components/datepicker.d.ts +5 -2
  93. package/dist/types/components/menu.d.ts +1 -0
  94. package/dist/types/components/slider.d.ts +1 -0
  95. package/dist/types/components/snackbar.d.ts +6 -0
  96. package/dist/types/components/timepicker.d.ts +4 -1
  97. package/dist/types/components/tooltip.d.ts +2 -1
  98. package/dist/types/modular.d.ts +1 -1
  99. package/package.json +1 -1
  100. package/src/sass/components/_carousel.scss +9 -7
  101. package/src/sass/components/_navbar.scss +11 -6
  102. package/src/sass/components/_page-footer.scss +0 -11
  103. package/src/sass/components/_progress.scss +25 -6
  104. package/src/sass/components/_snackbar.scss +1 -1
  105. package/src/sass/components/_timepicker.scss +2 -2
  106. package/src/sass/components/_toolbar.scss +1 -1
  107. package/src/sass/components/forms/_checkboxes.scss +2 -2
  108. package/src/sass/components/forms/_input-fields.scss +35 -15
  109. package/src/sass/components/forms/_radio-buttons.scss +2 -2
  110. package/src/sass/components/forms/_slider.scss +51 -29
  111. package/src/sass/components/forms/_switches.scss +3 -3
  112. package/src/sass/utilities/_helpers.scss +14 -0
  113. package/src/sass/utilities/_spacing.scss +29 -23
  114. package/src/sass/utilities/_visibility.scss +3 -2
  115. package/dist/js/chunks/chunk-74N6U5JJ.mjs.map +0 -7
  116. package/dist/js/chunks/chunk-AYYYWUJ4.mjs.map +0 -7
  117. package/dist/js/chunks/chunk-CDW6WIRT.mjs.map +0 -7
  118. package/dist/js/chunks/chunk-D4UZ4HFN.mjs.map +0 -7
  119. package/dist/js/chunks/chunk-EP3CVKB5.mjs.map +0 -7
  120. package/dist/js/chunks/chunk-GY2Z5CJ2.mjs.map +0 -7
  121. package/dist/js/chunks/chunk-I5KR22BY.mjs.map +0 -7
  122. package/dist/js/chunks/chunk-JKNPQQWY.mjs.map +0 -7
  123. package/dist/js/chunks/chunk-JODJAGFS.mjs.map +0 -7
  124. package/dist/js/chunks/chunk-LZVBJ33S.mjs.map +0 -7
  125. package/dist/js/chunks/chunk-PMBPAFAS.mjs +0 -7
  126. package/dist/js/chunks/chunk-TK6PX2GC.mjs.map +0 -7
  127. /package/dist/js/chunks/{chunk-IMUPRRI6.mjs.map → chunk-3VOK6J7U.mjs.map} +0 -0
  128. /package/dist/js/chunks/{chunk-A3BJA7V4.mjs.map → chunk-6WLSDZ4O.mjs.map} +0 -0
  129. /package/dist/js/chunks/{chunk-KR44BSYQ.mjs.map → chunk-DLWYKFEI.mjs.map} +0 -0
  130. /package/dist/js/chunks/{chunk-SLFNPY5M.mjs.map → chunk-EC63CHXU.mjs.map} +0 -0
  131. /package/dist/js/chunks/{chunk-7GKXUG4B.mjs.map → chunk-HNFSMIBY.mjs.map} +0 -0
  132. /package/dist/js/chunks/{chunk-VAS6JQ6P.mjs.map → chunk-PIJ2TAR3.mjs.map} +0 -0
  133. /package/dist/js/chunks/{chunk-JR24UB4X.mjs.map → chunk-PSSHQWCX.mjs.map} +0 -0
  134. /package/dist/js/chunks/{chunk-PIIAEYAJ.mjs.map → chunk-QDAL4IYN.mjs.map} +0 -0
  135. /package/dist/js/chunks/{chunk-FRB7TOCS.mjs.map → chunk-QV2JAWIZ.mjs.map} +0 -0
  136. /package/dist/js/chunks/{chunk-N3UHGN3N.mjs.map → chunk-QVVEWBOF.mjs.map} +0 -0
  137. /package/dist/js/chunks/{chunk-TYM6U5DY.mjs.map → chunk-UAEAQBRC.mjs.map} +0 -0
  138. /package/dist/js/chunks/{chunk-7UXHSYIA.mjs.map → chunk-UBLRRJ7N.mjs.map} +0 -0
  139. /package/dist/js/chunks/{chunk-JNPIWFJT.mjs.map → chunk-UNEMYWEW.mjs.map} +0 -0
  140. /package/dist/js/chunks/{chunk-XO5WX3TK.mjs.map → chunk-YDCS5S3J.mjs.map} +0 -0
@@ -271,12 +271,7 @@ var Expressive = (() => {
271
271
  button.type = "button";
272
272
  button.tabIndex = !!visibility ? 0 : -1;
273
273
  button.innerText = text;
274
- if (typeof callback === "function") {
275
- button.addEventListener("click", callback);
276
- button.addEventListener("keypress", (e) => {
277
- if (e.key === _Utils.keys.ENTER) callback(e);
278
- });
279
- }
274
+ if (typeof callback === "function") button.addEventListener("click", callback);
280
275
  container.append(button);
281
276
  }
282
277
  static _setAbsolutePosition(origin, container, position, margin, transitionMovement, align = "center") {
@@ -315,6 +310,13 @@ var Expressive = (() => {
315
310
  transitionMovement,
316
311
  align
317
312
  );
313
+ const parent = container.offsetParent;
314
+ if (parent && (parent !== document.body || getComputedStyle(parent).position !== "static")) {
315
+ const rect = parent.getBoundingClientRect();
316
+ const root = parent === document.scrollingElement;
317
+ newCoordinates.x -= rect.left + _Utils.getDocumentScrollLeft() + parent.clientLeft - (root ? 0 : parent.scrollLeft);
318
+ newCoordinates.y -= rect.top + _Utils.getDocumentScrollTop() + parent.clientTop - (root ? 0 : parent.scrollTop);
319
+ }
318
320
  container.style.top = newCoordinates.y + "px";
319
321
  container.style.left = newCoordinates.x + "px";
320
322
  return { x: xMovement, y: yMovement };
@@ -396,7 +398,7 @@ var Expressive = (() => {
396
398
  let instances = null;
397
399
  if (els instanceof Element) {
398
400
  instances = new classDef(els, options);
399
- } else if (!!els && els.length) {
401
+ } else if (els) {
400
402
  instances = [];
401
403
  for (let i = 0; i < els.length; i++) {
402
404
  instances.push(new classDef(els[i], options));
@@ -784,6 +786,7 @@ var Expressive = (() => {
784
786
  super(el, options, _Menu);
785
787
  this._pendingTimers = /* @__PURE__ */ new Set();
786
788
  this._transition = 0;
789
+ this._menuClickTargets = /* @__PURE__ */ new WeakMap();
787
790
  this._handleClick = (e) => {
788
791
  e.preventDefault();
789
792
  if (this.isOpen) {
@@ -812,11 +815,15 @@ var Expressive = (() => {
812
815
  }
813
816
  };
814
817
  this._handleDocumentClick = (e) => {
815
- const target = e.target;
818
+ const path = e.composedPath();
819
+ const menuTarget = this._menuClickTargets.get(e);
820
+ this._menuClickTargets.delete(e);
821
+ const target = menuTarget ?? (path[0] || e.target);
822
+ const inside = !!menuTarget || path.includes(this.menuEl) || this.menuEl?.contains(target);
816
823
  if (this._isSubmenuTriggerClick(target)) return;
817
- if (this.options.closeOnClick && this.menuEl?.contains(target) && !this.isTouchMoving) {
824
+ if (this.options.closeOnClick && inside && !this.isTouchMoving) {
818
825
  this.close();
819
- } else if (!this.menuEl?.contains(target)) {
826
+ } else if (!inside) {
820
827
  this._schedule(() => {
821
828
  if (this.isOpen) {
822
829
  this.close();
@@ -834,12 +841,13 @@ var Expressive = (() => {
834
841
  };
835
842
  this._handleDocumentTouchmove = (e) => {
836
843
  const target = e.target;
837
- if (this.menuEl?.contains(target)) {
844
+ if (e.composedPath().includes(this.menuEl) || this.menuEl?.contains(target)) {
838
845
  this.isTouchMoving = true;
839
846
  }
840
847
  };
841
848
  this._handleMenuClick = (e) => {
842
849
  const target = e.target;
850
+ this._menuClickTargets.set(e, target);
843
851
  const li = target.closest("li");
844
852
  if (li?.matches('.disabled, [aria-disabled="true"]')) {
845
853
  e.preventDefault();
@@ -1006,7 +1014,7 @@ var Expressive = (() => {
1006
1014
  this._animateOut();
1007
1015
  this._removeTemporaryEventHandlers();
1008
1016
  this.el.ariaExpanded = "false";
1009
- if (this.options.autoFocus && (root.activeElement === focused || !root.activeElement || root.activeElement === document.body)) {
1017
+ if (this.options.autoFocus && this.menuEl.contains(focused) && (root.activeElement === focused || this.el.ownerDocument.activeElement === this.el.ownerDocument.body)) {
1010
1018
  this.el.focus();
1011
1019
  }
1012
1020
  };
@@ -1098,6 +1106,7 @@ var Expressive = (() => {
1098
1106
  }
1099
1107
  _setupTemporaryEventHandlers() {
1100
1108
  document.body.addEventListener("click", this._handleDocumentClick);
1109
+ this.menuEl?.addEventListener("touchmove", this._handleDocumentTouchmove, { passive: true });
1101
1110
  document.body.addEventListener("touchmove", this._handleDocumentTouchmove, {
1102
1111
  passive: true
1103
1112
  });
@@ -1106,6 +1115,7 @@ var Expressive = (() => {
1106
1115
  }
1107
1116
  _removeTemporaryEventHandlers() {
1108
1117
  document.body.removeEventListener("click", this._handleDocumentClick);
1118
+ this.menuEl?.removeEventListener("touchmove", this._handleDocumentTouchmove);
1109
1119
  document.body.removeEventListener("touchmove", this._handleDocumentTouchmove);
1110
1120
  this.menuEl?.removeEventListener("keydown", this._handleMenuKeydown);
1111
1121
  window.removeEventListener("resize", this._handleWindowResize);
@@ -1539,7 +1549,6 @@ var Expressive = (() => {
1539
1549
  const inputText = this.el.value.toLocaleLowerCase();
1540
1550
  this._resetAutocomplete();
1541
1551
  if (inputText.length >= this.options.minLength) {
1542
- this.isOpen = true;
1543
1552
  this._renderMenu();
1544
1553
  this._announce(this.menuItems.length ? this.options.i18n.results(this.menuItems.length) : this.options.i18n.noResults);
1545
1554
  }
@@ -1633,6 +1642,7 @@ var Expressive = (() => {
1633
1642
  }
1634
1643
  this._removeEventHandlers();
1635
1644
  this.menu.destroy();
1645
+ this.isOpen = false;
1636
1646
  this._removeMenu();
1637
1647
  this._statusInfo.remove();
1638
1648
  this._announcer.remove();
@@ -1680,6 +1690,16 @@ var Expressive = (() => {
1680
1690
  ..._Autocomplete.defaults.menuOptions,
1681
1691
  ...this.options.menuOptions
1682
1692
  };
1693
+ const userOnOpenStart = menuOptions.onOpenStart;
1694
+ const userOnCloseStart = menuOptions.onCloseStart;
1695
+ menuOptions.onOpenStart = (el) => {
1696
+ this.isOpen = true;
1697
+ if (typeof userOnOpenStart === "function") userOnOpenStart.call(this.menu, el);
1698
+ };
1699
+ menuOptions.onCloseStart = (el) => {
1700
+ this.isOpen = false;
1701
+ if (typeof userOnCloseStart === "function") userOnCloseStart.call(this.menu, el);
1702
+ };
1683
1703
  const userOnItemClick = menuOptions.onItemClick;
1684
1704
  menuOptions.onItemClick = (li) => {
1685
1705
  if (!li) return;
@@ -1692,10 +1712,7 @@ var Expressive = (() => {
1692
1712
  const label = this.el.parentElement.querySelector("label");
1693
1713
  if (label) this.el.after(label);
1694
1714
  this.el.removeEventListener("click", this.menu._handleClick);
1695
- if (!this.options.isMultiSelect && !(this.options.selected.length === 0)) {
1696
- const selectedValue = this.menuItems.filter((value) => value.id === this.selectedValues[0].id);
1697
- this.el.value = selectedValue[0].text;
1698
- }
1715
+ if (!this.options.isMultiSelect) this._refreshInputText();
1699
1716
  if (this.el.value) this.selectOption(this.el.value);
1700
1717
  const div = document.createElement("div");
1701
1718
  div.classList.add("status-info");
@@ -1723,7 +1740,6 @@ var Expressive = (() => {
1723
1740
  this.container.replaceChildren();
1724
1741
  this._resetCurrentElementPosition();
1725
1742
  this.oldVal = null;
1726
- this.isOpen = false;
1727
1743
  this._pointerDown = false;
1728
1744
  }
1729
1745
  _highlightPartialText(input, label) {
@@ -1841,7 +1857,7 @@ var Expressive = (() => {
1841
1857
  }
1842
1858
  }
1843
1859
  _triggerChanged() {
1844
- this.el.dispatchEvent(new Event("change"));
1860
+ this.el.dispatchEvent(new Event("change", { bubbles: true, cancelable: true, composed: true }));
1845
1861
  if (typeof this.options.onAutocomplete === "function")
1846
1862
  this.options.onAutocomplete.call(this, this.selectedValues);
1847
1863
  }
@@ -1950,7 +1966,7 @@ var Expressive = (() => {
1950
1966
  this._handleInputKeydown = (e) => {
1951
1967
  _Chips._keydown = true;
1952
1968
  if (e.key === Utils.keys.ENTER) {
1953
- if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) {
1969
+ if (this.hasAutocomplete && this.autocomplete?.isOpen && this.autocomplete.container.querySelector('[role="option"]')) {
1954
1970
  return;
1955
1971
  }
1956
1972
  e.preventDefault();
@@ -2016,6 +2032,9 @@ var Expressive = (() => {
2016
2032
  return this.chipsData;
2017
2033
  }
2018
2034
  destroy() {
2035
+ if (this.autocomplete && Autocomplete.getInstance(this._input) === this.autocomplete) {
2036
+ this.autocomplete.destroy();
2037
+ }
2019
2038
  if (this.options.allowUserInput) {
2020
2039
  this._removeEventHandlers();
2021
2040
  }
@@ -2081,7 +2100,7 @@ var Expressive = (() => {
2081
2100
  }
2082
2101
  }
2083
2102
  _renderChip(chip) {
2084
- if (!chip.id) return;
2103
+ if (!chip.id && chip.id !== 0) return;
2085
2104
  const label = chip.text || chip.id;
2086
2105
  const renderedChip = document.createElement("span");
2087
2106
  renderedChip.classList.add("chip");
@@ -2115,14 +2134,16 @@ var Expressive = (() => {
2115
2134
  }
2116
2135
  _setupAutocomplete() {
2117
2136
  this.options.autocompleteOptions.onAutocomplete = (items) => {
2118
- if (items.length > 0)
2137
+ if (_Chips.getInstance(this.el) !== this) return;
2138
+ if (items.length > 0) {
2119
2139
  this.addChip({
2120
2140
  id: items[0].id,
2121
2141
  text: items[0].text,
2122
2142
  image: items[0].image
2123
2143
  });
2124
- this._input.value = "";
2125
- this._input.focus();
2144
+ this._input.value = "";
2145
+ this._input.focus();
2146
+ }
2126
2147
  };
2127
2148
  this.autocomplete = Autocomplete.init(this._input, this.options.autocompleteOptions);
2128
2149
  }
@@ -2143,6 +2164,7 @@ var Expressive = (() => {
2143
2164
  if (this._label && this._input) this._label.setAttribute("for", this._input.getAttribute("id"));
2144
2165
  }
2145
2166
  _setPlaceholder() {
2167
+ if (!this._input) return;
2146
2168
  if (this.chipsData !== void 0 && !this.chipsData.length && this.options.placeholder) {
2147
2169
  this._input.placeholder = this.options.placeholder;
2148
2170
  } else if ((this.chipsData === void 0 || !!this.chipsData.length) && this.options.secondaryPlaceholder) {
@@ -2150,7 +2172,7 @@ var Expressive = (() => {
2150
2172
  }
2151
2173
  }
2152
2174
  _isValidAndNotExist(chip) {
2153
- const isValid = !!chip.id;
2175
+ const isValid = !!chip.id || chip.id === 0;
2154
2176
  const doesNotExist = !this.chipsData.some((item) => item.id == chip.id);
2155
2177
  return isValid && doesNotExist;
2156
2178
  }
@@ -2163,7 +2185,8 @@ var Expressive = (() => {
2163
2185
  const renderedChip = this._renderChip(chip);
2164
2186
  this._chips.push(renderedChip);
2165
2187
  this.chipsData.push(chip);
2166
- this._input.before(renderedChip);
2188
+ if (this._input) this._input.before(renderedChip);
2189
+ else this.el.append(renderedChip);
2167
2190
  this._setPlaceholder();
2168
2191
  if (typeof this.options.onChipAdd === "function") {
2169
2192
  this.options.onChipAdd(this.el, renderedChip);
@@ -2234,6 +2257,7 @@ var Expressive = (() => {
2234
2257
 
2235
2258
  // src/ts/components/slider.ts
2236
2259
  var _defaults6 = {};
2260
+ var _authored = /* @__PURE__ */ new WeakMap();
2237
2261
  var Slider = class _Slider extends Component {
2238
2262
  constructor(el, options) {
2239
2263
  super(el, options, _Slider);
@@ -2302,6 +2326,18 @@ var Expressive = (() => {
2302
2326
  this._removeEventHandlers();
2303
2327
  this._removeThumb();
2304
2328
  this.el["Expressive_Slider"] = void 0;
2329
+ const host = this._host();
2330
+ for (const el of [this.el, host]) {
2331
+ for (const name in _authored.get(el)) el.style.setProperty(name, _authored.get(el)[name]);
2332
+ _authored.delete(el);
2333
+ }
2334
+ host?.querySelectorAll('input[type="range"]').forEach((el) => el["Expressive_Slider"]?._sync());
2335
+ }
2336
+ _set(el, name, value) {
2337
+ const authored = _authored.get(el) ?? {};
2338
+ _authored.set(el, authored);
2339
+ authored[name] ?? (authored[name] = el.style.getPropertyValue(name));
2340
+ el.style.setProperty(name, value);
2305
2341
  }
2306
2342
  // Eleven listeners used to cover four stages, because each one was written
2307
2343
  // twice - once for mouse, once for touch. One of the touch spellings,
@@ -2372,25 +2408,28 @@ var Expressive = (() => {
2372
2408
  const handle = parseFloat(style.getPropertyValue("--md-comp-slider-handle-width")) || 4;
2373
2409
  const length = vertical ? height : width;
2374
2410
  const position = handle / 2 + percent * (length - handle);
2375
- this.el.style.setProperty("--md-comp-slider-active-fraction", fraction);
2376
- this.el.style.setProperty("--md-comp-slider-active-position", `${position}px`);
2411
+ this._set(this.el, "--md-comp-slider-active-fraction", fraction);
2412
+ this._set(this.el, "--md-comp-slider-active-position", `${position}px`);
2377
2413
  const host = this._host();
2378
2414
  const peers = host?.querySelectorAll('input[type="range"]');
2379
2415
  if (host && peers && peers.length === 2) {
2380
2416
  const nums = Array.from(peers).map((el) => this._fraction(el));
2381
- host.style.setProperty("--md-comp-slider-start-fraction", `${Math.min(...nums) * 100}%`);
2382
- host.style.setProperty("--md-comp-slider-end-fraction", `${Math.max(...nums) * 100}%`);
2383
- host.style.setProperty("--md-comp-slider-start-position", `${handle / 2 + Math.min(...nums) * (length - handle)}px`);
2384
- host.style.setProperty("--md-comp-slider-end-position", `${handle / 2 + Math.max(...nums) * (length - handle)}px`);
2417
+ this._set(host, "--md-comp-slider-start-fraction", `${Math.min(...nums) * 100}%`);
2418
+ this._set(host, "--md-comp-slider-end-fraction", `${Math.max(...nums) * 100}%`);
2419
+ this._set(host, "--md-comp-slider-start-position", `${handle / 2 + Math.min(...nums) * (length - handle)}px`);
2420
+ this._set(host, "--md-comp-slider-end-position", `${handle / 2 + Math.max(...nums) * (length - handle)}px`);
2385
2421
  }
2386
2422
  if (host?.classList.contains("stops")) {
2387
2423
  const parsedMax = parseFloat(this.el.max);
2388
2424
  const max = Number.isNaN(parsedMax) ? 100 : parsedMax;
2389
2425
  const min = parseFloat(this.el.min) || 0;
2390
2426
  const step = parseFloat(this.el.step);
2391
- if (step > 0 && Number.isFinite(step)) {
2392
- const n = Math.round((max - min) / step) + 1;
2393
- host.style.setProperty("--md-comp-slider-stop-count", String(Math.max(2, n)));
2427
+ const stops = step > 0 && Number.isFinite(step) && max > min;
2428
+ this._set(host, "--md-comp-slider-stop-count", stops ? String(Math.floor((max - min) / step + 1e-9) + 1) : "");
2429
+ this._set(host, "--md-comp-slider-stop-spacing", stops ? `${(length - handle) * step / (max - min)}px` : "");
2430
+ if (peers?.length === 1) {
2431
+ this._set(host, "--md-comp-slider-active-position", `${position}px`);
2432
+ this._set(host, "--md-comp-slider-track-center", `${top + height / 2}px`);
2394
2433
  }
2395
2434
  }
2396
2435
  this.value.textContent = this.el.value;
@@ -2483,6 +2522,7 @@ var Expressive = (() => {
2483
2522
  // src/ts/behaviors/sheetDrag.ts
2484
2523
  var DISMISS_DISTANCE = 96;
2485
2524
  var DISMISS_VELOCITY = 0.5;
2525
+ var FLICK_TIMEOUT = 100;
2486
2526
  var DRAG_SLOP = 4;
2487
2527
  function installSheetDrag(config) {
2488
2528
  const coord = (event) => config.axis === "x" ? event.clientX : event.clientY;
@@ -2519,6 +2559,7 @@ var Expressive = (() => {
2519
2559
  start: coord(event),
2520
2560
  last: coord(event),
2521
2561
  lastT: Date.now(),
2562
+ velocity: 0,
2522
2563
  shift: 0
2523
2564
  };
2524
2565
  observer.observe(document, { childList: true, subtree: true, attributes: true, attributeFilter: ["open"], attributeOldValue: true });
@@ -2531,8 +2572,12 @@ var Expressive = (() => {
2531
2572
  }
2532
2573
  const delta = coord(event) - drag.start;
2533
2574
  drag.shift = drag.direction === 1 ? Math.max(0, delta) : Math.min(0, delta);
2534
- drag.last = coord(event);
2535
- drag.lastT = Date.now();
2575
+ if (coord(event) !== drag.last) {
2576
+ const now = Date.now();
2577
+ drag.velocity = (coord(event) - drag.last) / Math.max(1, now - drag.lastT);
2578
+ drag.last = coord(event);
2579
+ drag.lastT = now;
2580
+ }
2536
2581
  drag.dialog.style.setProperty(config.property, `${drag.shift}px`);
2537
2582
  };
2538
2583
  const onUp = (event) => {
@@ -2542,13 +2587,14 @@ var Expressive = (() => {
2542
2587
  onCancel();
2543
2588
  return;
2544
2589
  }
2590
+ onMove(event);
2545
2591
  drag = null;
2546
2592
  observer.disconnect();
2547
2593
  held.dialog.style.transition = "";
2548
- const dt = Math.max(1, Date.now() - held.lastT);
2549
- const velocity = (coord(event) - held.last) / dt;
2550
- config.onRelease?.(Math.abs(held.shift) > DRAG_SLOP);
2551
- const dismiss = held.direction === 1 ? held.shift > DISMISS_DISTANCE || velocity > DISMISS_VELOCITY : held.shift < -DISMISS_DISTANCE || velocity < -DISMISS_VELOCITY;
2594
+ const velocity = Date.now() - held.lastT < FLICK_TIMEOUT ? held.velocity : 0;
2595
+ const dragged = Math.abs(held.shift) > DRAG_SLOP;
2596
+ config.onRelease?.(dragged);
2597
+ const dismiss = dragged && (held.direction === 1 ? held.shift > DISMISS_DISTANCE || velocity > DISMISS_VELOCITY : held.shift < -DISMISS_DISTANCE || velocity < -DISMISS_VELOCITY);
2552
2598
  if (dismiss && held.dialog.open) held.dialog.close();
2553
2599
  held.dialog.style.setProperty(config.property, "0px");
2554
2600
  };
@@ -2743,7 +2789,10 @@ var Expressive = (() => {
2743
2789
  this._onIntersect = (entries) => {
2744
2790
  const entry = entries[0];
2745
2791
  if (!entry) return;
2746
- this.el.classList.toggle("collapsed", !entry.isIntersecting);
2792
+ this.el.classList.toggle(
2793
+ "collapsed",
2794
+ !entry.isIntersecting && entry.boundingClientRect.top < this.el.getBoundingClientRect().top
2795
+ );
2747
2796
  };
2748
2797
  this._onSearchViewClose = () => {
2749
2798
  this._searchOpen = this._view.open;
@@ -2790,8 +2839,8 @@ var Expressive = (() => {
2790
2839
  if (typeof IntersectionObserver === "undefined") return;
2791
2840
  this._sentinel = document.createElement("span");
2792
2841
  this._sentinel.setAttribute("aria-hidden", "true");
2793
- this._sentinel.style.cssText = "display:block;width:100%;height:1px;margin-top:-1px;pointer-events:none;visibility:hidden";
2794
- this.el.insertAdjacentElement("beforebegin", this._sentinel);
2842
+ this._sentinel.style.cssText = "display:block;height:0;position:relative;top:-64px;pointer-events:none;visibility:hidden";
2843
+ this.el.insertAdjacentElement("afterend", this._sentinel);
2795
2844
  this._observer = new IntersectionObserver(this._onIntersect);
2796
2845
  this._observer.observe(this._sentinel);
2797
2846
  }
@@ -3218,10 +3267,6 @@ var Expressive = (() => {
3218
3267
  this._dragStartX = e.clientX;
3219
3268
  this._dragStartY = e.clientY;
3220
3269
  this._dragStartScroll = this._vertical ? this._scroller.scrollTop : this._scroller.scrollLeft;
3221
- try {
3222
- this._scroller.setPointerCapture(e.pointerId);
3223
- } catch {
3224
- }
3225
3270
  };
3226
3271
  this._handleTrackPointerMove = (e) => {
3227
3272
  if (!this.pressed || e.pointerId !== this._dragPointerId) return;
@@ -3233,6 +3278,10 @@ var Expressive = (() => {
3233
3278
  if (Math.abs(primaryDelta) < 6 || Math.abs(primaryDelta) <= Math.abs(crossDelta)) return;
3234
3279
  this.dragged = true;
3235
3280
  this.el.classList.add("dragging");
3281
+ try {
3282
+ this._scroller.setPointerCapture(e.pointerId);
3283
+ } catch {
3284
+ }
3236
3285
  }
3237
3286
  if (this._vertical) this._scroller.scrollTop = this._dragStartScroll - deltaY;
3238
3287
  else this._scroller.scrollLeft = this._dragStartScroll - deltaX;
@@ -3262,7 +3311,7 @@ var Expressive = (() => {
3262
3311
  e.stopImmediatePropagation();
3263
3312
  };
3264
3313
  this._handleTrackDragStart = (e) => {
3265
- if (e.target.closest("img, picture, video")) e.preventDefault();
3314
+ if (e.target.closest("a, img, picture, video")) e.preventDefault();
3266
3315
  };
3267
3316
  this._handleItemResize = (e) => {
3268
3317
  if (this._alignAfterResize && !this.pressed && e.propertyName === "flex-basis" && this.images.includes(e.target)) {
@@ -3318,7 +3367,7 @@ var Expressive = (() => {
3318
3367
  if (!this._started || !this.images.length) return;
3319
3368
  this._syncAdaptiveMode();
3320
3369
  this._syncLayoutRoles(this.center);
3321
- this._scrollToIndex(this.center, false);
3370
+ if (!this.pressed) this._scrollToIndex(this.center, false);
3322
3371
  this._updateParallax();
3323
3372
  };
3324
3373
  this._finishScroll = () => {
@@ -3502,9 +3551,9 @@ var Expressive = (() => {
3502
3551
  });
3503
3552
  this._scroller.addEventListener("pointerdown", this._handleTrackPointerDown);
3504
3553
  this._scroller.addEventListener("wheel", this._handleNativeScroll, { passive: true });
3505
- this._scroller.addEventListener("pointermove", this._handleTrackPointerMove);
3506
- this._scroller.addEventListener("pointerup", this._handleTrackPointerUp);
3507
- this._scroller.addEventListener("pointercancel", this._handleTrackPointerUp);
3554
+ document.addEventListener("pointermove", this._handleTrackPointerMove);
3555
+ document.addEventListener("pointerup", this._handleTrackPointerUp);
3556
+ document.addEventListener("pointercancel", this._handleTrackPointerUp);
3508
3557
  this._scroller.addEventListener("click", this._handleTrackClick, true);
3509
3558
  this._scroller.addEventListener("dragstart", this._handleTrackDragStart);
3510
3559
  this._scroller.addEventListener("transitionend", this._handleItemResize);
@@ -3523,9 +3572,9 @@ var Expressive = (() => {
3523
3572
  this._scroller.removeEventListener("scroll", this._handleTrackScroll);
3524
3573
  this._scroller.removeEventListener("pointerdown", this._handleTrackPointerDown);
3525
3574
  this._scroller.removeEventListener("wheel", this._handleNativeScroll);
3526
- this._scroller.removeEventListener("pointermove", this._handleTrackPointerMove);
3527
- this._scroller.removeEventListener("pointerup", this._handleTrackPointerUp);
3528
- this._scroller.removeEventListener("pointercancel", this._handleTrackPointerUp);
3575
+ document.removeEventListener("pointermove", this._handleTrackPointerMove);
3576
+ document.removeEventListener("pointerup", this._handleTrackPointerUp);
3577
+ document.removeEventListener("pointercancel", this._handleTrackPointerUp);
3529
3578
  this._scroller.removeEventListener("click", this._handleTrackClick, true);
3530
3579
  this._scroller.removeEventListener("dragstart", this._handleTrackDragStart);
3531
3580
  this._scroller.removeEventListener("transitionend", this._handleItemResize);
@@ -4335,8 +4384,7 @@ var Expressive = (() => {
4335
4384
  this._values.forEach((value) => this._deselectValue(value));
4336
4385
  }
4337
4386
  _isValueSelected(value) {
4338
- const realValues = this.getSelectedValues();
4339
- return realValues.some((realValue) => realValue === value.el.value);
4387
+ return value.el.selected;
4340
4388
  }
4341
4389
  _toggleEntryFromArray(value) {
4342
4390
  if (this._isValueSelected(value)) this._deselectValue(value);
@@ -4561,9 +4609,7 @@ var Expressive = (() => {
4561
4609
  this._randId = null;
4562
4610
  this._focusedDate = null;
4563
4611
  this._handleInputClick = (e) => {
4564
- if (e.type == "date") {
4565
- e.preventDefault();
4566
- }
4612
+ if (e.target.type == "date" && (this.options.openByDefault || this.options.container)) e.preventDefault();
4567
4613
  this._batchDraws(() => {
4568
4614
  this.setDateFromInput(e.target);
4569
4615
  this.draw();
@@ -4673,26 +4719,8 @@ var Expressive = (() => {
4673
4719
  this.gotoYear(e.target.value);
4674
4720
  };
4675
4721
  this._handleInputChange = (e) => {
4676
- let date;
4677
- const el = e.target;
4678
4722
  if (e["detail"]?.firedBy === this) return;
4679
- if (el == this.endDateEl && !this.date) return;
4680
- if (this.options.parse) {
4681
- date = this.options.parse(
4682
- e.target.value,
4683
- typeof this.options.format === "function" ? this.options.format(new Date(this.el.value)) : this.options.format
4684
- );
4685
- } else {
4686
- date = _Datepicker._parseDate(e.target.value);
4687
- }
4688
- if (_Datepicker._isDate(date)) {
4689
- if (el == this.endDateEl && date < this.date) return this.setInputValue(el, this.endDate);
4690
- this.setDate(date, false, el == this.endDateEl, true);
4691
- if (e.type == "date") {
4692
- this.setDataDate(e, date);
4693
- this.setInputValues();
4694
- }
4695
- }
4723
+ this.setDateFromInput(e.target);
4696
4724
  };
4697
4725
  this._finishSelection = () => {
4698
4726
  this.setInputValues();
@@ -4724,7 +4752,7 @@ var Expressive = (() => {
4724
4752
  this._insertHTMLIntoDOM();
4725
4753
  this._setupEventHandlers();
4726
4754
  if (!this.options.defaultDate) {
4727
- this.options.defaultDate = _Datepicker._parseDate(this.el.value);
4755
+ this.options.defaultDate = this._parseInput(this.el.value);
4728
4756
  }
4729
4757
  const defDate = this.options.defaultDate;
4730
4758
  if (_Datepicker._isDate(defDate)) {
@@ -4783,6 +4811,13 @@ var Expressive = (() => {
4783
4811
  const date = /* @__PURE__ */ new Date(value + "T00:00:00");
4784
4812
  return date.getDate() === Number(value.slice(-2)) ? date : /* @__PURE__ */ new Date(NaN);
4785
4813
  }
4814
+ _parseInput(value) {
4815
+ if (!value.trim() || !this.options.parse) return _Datepicker._parseDate(value);
4816
+ return this.options.parse(
4817
+ value,
4818
+ typeof this.options.format === "string" ? this.options.format : ""
4819
+ );
4820
+ }
4786
4821
  static _isWeekend(date) {
4787
4822
  const day = date.getDay();
4788
4823
  return day === 0 || day === 6;
@@ -4892,8 +4927,22 @@ var Expressive = (() => {
4892
4927
  * Sets date from input field.
4893
4928
  */
4894
4929
  setDateFromInput(el) {
4895
- const date = _Datepicker._parseDate(el.value);
4896
- this.setDate(date, false, el == this.endDateEl, true);
4930
+ if (el.type === "date") this.setDataDate(el, _Datepicker._parseDate(el.value));
4931
+ if ((this.options.isDateRange || !this.options.isMultipleSelection) && !el.value.trim()) {
4932
+ this.setSingleDate(null, el === this.endDateEl);
4933
+ this.draw();
4934
+ return;
4935
+ }
4936
+ const parsedDate = this._parseInput(el.value);
4937
+ if (!_Datepicker._isDate(parsedDate)) return;
4938
+ const date = new Date(parsedDate.getTime());
4939
+ _Datepicker._setToStartOfDay(date);
4940
+ const isEndDate = el === this.endDateEl;
4941
+ if (this.options.isDateRange && (isEndDate ? this.date && date < this.date : this.endDate && date > this.endDate)) {
4942
+ this.setInputValue(el, isEndDate ? this.endDate : this.date);
4943
+ return;
4944
+ }
4945
+ this.setDate(date, false, isEndDate, true);
4897
4946
  }
4898
4947
  /**
4899
4948
  * Set a date on the datepicker.
@@ -4965,7 +5014,7 @@ var Expressive = (() => {
4965
5014
  * Sets the data-date attribute on the date input field
4966
5015
  */
4967
5016
  setDataDate(el, date) {
4968
- el.setAttribute("data-date", this.toString(date));
5017
+ el.setAttribute("data-date", _Datepicker._isDate(date) ? this.toString(date) : "");
4969
5018
  }
4970
5019
  /**
4971
5020
  * Sets dates on the input values.
@@ -4991,16 +5040,15 @@ var Expressive = (() => {
4991
5040
  */
4992
5041
  setInputValue(el, date) {
4993
5042
  if (!el) return;
5043
+ if (el.type == "date") this.setDataDate(el, date);
4994
5044
  if (!_Datepicker._isDate(date)) {
4995
5045
  el.value = "";
4996
- if (el.type === "date") el.setAttribute("data-date", "");
4997
5046
  } else if (el.type == "date") {
4998
- this.setDataDate(el, date);
4999
5047
  el.value = this.formatDate(date, "yyyy-mm-dd");
5000
5048
  } else {
5001
5049
  el.value = this.toString(date);
5002
5050
  }
5003
- this.el.dispatchEvent(
5051
+ el.dispatchEvent(
5004
5052
  new CustomEvent("change", {
5005
5053
  bubbles: true,
5006
5054
  cancelable: true,
@@ -5091,7 +5139,7 @@ var Expressive = (() => {
5091
5139
  cells += 7 - after;
5092
5140
  let isWeekSelected = false;
5093
5141
  for (let i = 0, r = 0; i < cells; i++) {
5094
- const day = new Date(year, month, 1 + (i - before)), isToday = _Datepicker._compareDates(day, now), hasEvent = this.options.events.indexOf(day.toDateString()) !== -1, isEmpty = i < before || i >= days + before, isStartRange = this.options.startRange && _Datepicker._compareDates(this.options.startRange, day), isEndRange = this.options.endRange && _Datepicker._compareDates(this.options.endRange, day), isInRange = this.options.startRange && this.options.endRange && this.options.startRange < day && day < this.options.endRange, isDisabled = this.options.minDate && day < this.options.minDate || this.options.maxDate && day > this.options.maxDate || this.options.disableWeekends && _Datepicker._isWeekend(day) || this.options.disableDayFn && this.options.disableDayFn(day), isDateRangeStart = this.options.isDateRange && this.date && this.endDate && _Datepicker._compareDates(this.date, day), isDateRangeEnd = this.options.isDateRange && this.endDate && _Datepicker._compareDates(this.endDate, day), isDateRange = this.options.isDateRange && _Datepicker._isDate(this.endDate) && _Datepicker._compareWithinRange(day, this.date, this.endDate);
5142
+ const day = new Date(year, month, 1 + (i - before)), isToday = _Datepicker._compareDates(day, now), hasEvent = this.options.events.indexOf(day.toDateString()) !== -1, isEmpty = i < before || i >= days + before, isStartRange = this.options.startRange && _Datepicker._compareDates(this.options.startRange, day), isEndRange = this.options.endRange && _Datepicker._compareDates(this.options.endRange, day), isInRange = this.options.startRange && this.options.endRange && this.options.startRange < day && day < this.options.endRange, isDisabled = this.options.minDate && day < this.options.minDate || this.options.maxDate && day > this.options.maxDate || this.options.disableWeekends && _Datepicker._isWeekend(day) || this.options.disableDayFn && this.options.disableDayFn(day), isDateRangeStart = this.options.isDateRange && this.date && this.endDate && _Datepicker._compareDates(this.date, day), isDateRangeEnd = this.options.isDateRange && this.endDate && _Datepicker._compareDates(this.endDate, day), isDateRange = this.options.isDateRange && _Datepicker._isDate(this.date) && _Datepicker._isDate(this.endDate) && _Datepicker._compareWithinRange(day, this.date, this.endDate);
5095
5143
  let dayNumber = 1 + (i - before), monthNumber = month, yearNumber = year;
5096
5144
  let isSelected = false;
5097
5145
  if (_Datepicker._isDate(this.date)) {
@@ -5526,6 +5574,7 @@ var Expressive = (() => {
5526
5574
  createDateInput() {
5527
5575
  const dateInput = this.el.cloneNode(true);
5528
5576
  dateInput.removeAttribute("id");
5577
+ dateInput.classList.add("no-autoinit");
5529
5578
  dateInput.addEventListener("click", this._handleInputClick);
5530
5579
  dateInput.addEventListener("keydown", this._handleInputKeydown);
5531
5580
  dateInput.addEventListener("change", this._handleInputChange);
@@ -6088,8 +6137,19 @@ var Expressive = (() => {
6088
6137
  }
6089
6138
  };
6090
6139
  this._onKeyDown = (e) => {
6091
- if (e.key !== "Escape") return;
6092
- if (this.isExpanded && this._isModal()) this.collapse();
6140
+ if (e.key !== "Escape" || e.defaultPrevented) return;
6141
+ if (this.isExpanded && this._isModal()) {
6142
+ const root = this.el.getRootNode();
6143
+ const restoreFocus = this.el.contains(root.activeElement);
6144
+ let focused = root.activeElement;
6145
+ while (focused?.shadowRoot?.activeElement) focused = focused.shadowRoot.activeElement;
6146
+ this.collapse();
6147
+ let active = root.activeElement;
6148
+ while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
6149
+ if (!this.isExpanded && restoreFocus && active === focused) {
6150
+ this._toggle?.focus();
6151
+ }
6152
+ }
6093
6153
  };
6094
6154
  this.el["Expressive_NavigationRail"] = this;
6095
6155
  this.options = {
@@ -6449,6 +6509,7 @@ var Expressive = (() => {
6449
6509
  /** Whether the dial (ticks + SVG + AM/PM buttons) has been built yet. */
6450
6510
  this._clockBuilt = false;
6451
6511
  this._handleInputClick = () => {
6512
+ this._updateTimeFromInput();
6452
6513
  this._ensureClockBuilt();
6453
6514
  if (this.displayPlugin) this.displayPlugin.show();
6454
6515
  this.inputHours.focus();
@@ -6457,10 +6518,7 @@ var Expressive = (() => {
6457
6518
  this._handleInputKeydown = (e) => {
6458
6519
  if (e.key === Utils.keys.ENTER) {
6459
6520
  e.preventDefault();
6460
- this._ensureClockBuilt();
6461
- if (this.displayPlugin) this.displayPlugin.show();
6462
- this.inputHours.focus();
6463
- if (typeof this.options.onInputInteraction === "function") this.options.onInputInteraction.call(this);
6521
+ this._handleInputClick();
6464
6522
  }
6465
6523
  };
6466
6524
  this._handleClockClickStart = (e) => {
@@ -6504,7 +6562,9 @@ var Expressive = (() => {
6504
6562
  this.inputMinutes.focus();
6505
6563
  this.showView("minutes", this.options.duration / 2);
6506
6564
  } else {
6507
- setTimeout(() => {
6565
+ clearTimeout(this._autoSubmitTimer);
6566
+ this._autoSubmitTimer = setTimeout(() => {
6567
+ this._autoSubmitTimer = null;
6508
6568
  if (this.options.autoSubmit) this.done();
6509
6569
  }, this.options.duration / 2);
6510
6570
  }
@@ -6556,6 +6616,7 @@ var Expressive = (() => {
6556
6616
  const input = event.target;
6557
6617
  const isHours = input === this.inputHours;
6558
6618
  if (!isHours && input !== this.inputMinutes) return;
6619
+ this._cancelClockReset();
6559
6620
  const value = Number(input.value);
6560
6621
  const min = isHours && this.options.twelveHour ? 1 : 0;
6561
6622
  const max = isHours ? this.options.twelveHour ? 12 : 23 : 59;
@@ -6624,6 +6685,10 @@ var Expressive = (() => {
6624
6685
  return el["Expressive_Timepicker"];
6625
6686
  }
6626
6687
  destroy() {
6688
+ clearTimeout(this._autoSubmitTimer);
6689
+ clearTimeout(this.toggleViewTimer);
6690
+ clearTimeout(this.vibrateTimer);
6691
+ this._cancelClockReset();
6627
6692
  this._removeEventHandlers();
6628
6693
  this.displayPlugin?.destroy();
6629
6694
  this.containerEl.remove();
@@ -6810,6 +6875,7 @@ var Expressive = (() => {
6810
6875
  }
6811
6876
  }
6812
6877
  _updateTimeFromInput() {
6878
+ this._cancelClockReset();
6813
6879
  let value = ((this.el.value || this.options.defaultTime || "") + "").trim().toUpperCase().split(":");
6814
6880
  const period = value[1]?.match(/AM|PM/)?.[0];
6815
6881
  value[1] = value[1]?.replace(/AM|PM/, "");
@@ -6827,12 +6893,17 @@ var Expressive = (() => {
6827
6893
  this.inputMinutes.value = _Timepicker._addLeadingZero(this.minutes);
6828
6894
  this._updateAmPmView();
6829
6895
  }
6896
+ _cancelClockReset() {
6897
+ clearTimeout(this._clockResetTimer);
6898
+ this._clockResetTimer = null;
6899
+ this._canvas?.classList.remove("timepicker-canvas-out");
6900
+ }
6830
6901
  resetClock(delay) {
6902
+ this._cancelClockReset();
6831
6903
  const view = this.currentView, value = this[view], isHours = view === "hours", unit = Math.PI / (isHours ? 6 : 30), radian = value * unit, radius = isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius, x = Math.sin(radian) * radius, y = -Math.cos(radian) * radius;
6832
6904
  if (delay) {
6833
6905
  this._canvas?.classList.add("timepicker-canvas-out");
6834
- setTimeout(() => {
6835
- this._canvas?.classList.remove("timepicker-canvas-out");
6906
+ this._clockResetTimer = setTimeout(() => {
6836
6907
  this.setHand(x, y);
6837
6908
  }, delay);
6838
6909
  } else {
@@ -6851,6 +6922,7 @@ var Expressive = (() => {
6851
6922
  this.setClockAttributes(radian, radius);
6852
6923
  }
6853
6924
  setHand(x, y, roundBy5 = false) {
6925
+ this._cancelClockReset();
6854
6926
  const isHours = this.currentView === "hours", unit = Math.PI / (isHours || roundBy5 ? 6 : 30), z = Math.sqrt(x * x + y * y), inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2;
6855
6927
  let radian = Math.atan2(x, -y), radius = inner ? this.options.innerRadius : this.options.outerRadius;
6856
6928
  if (this.options.twelveHour) {
@@ -6971,6 +7043,7 @@ var Expressive = (() => {
6971
7043
  constructor(options = {}) {
6972
7044
  this._dismissed = false;
6973
7045
  this._returnFocus = null;
7046
+ this._restoreElement = null;
6974
7047
  this.options = {
6975
7048
  ..._Snackbar.defaults,
6976
7049
  ...options
@@ -6985,22 +7058,20 @@ var Expressive = (() => {
6985
7058
  while (_Snackbar._snackbars.length > 0) {
6986
7059
  const snackbar = _Snackbar._snackbars.shift();
6987
7060
  snackbar._dismissed = true;
6988
- clearTimeout(snackbar.counterTimeout);
6989
- snackbar._restoreFocus();
6990
- snackbar.el.remove();
7061
+ snackbar._restoreFocus(true);
6991
7062
  }
6992
7063
  let focused = document.activeElement;
6993
7064
  while (focused?.shadowRoot?.activeElement) focused = focused.shadowRoot.activeElement;
6994
7065
  this._returnFocus = focused instanceof HTMLElement ? focused : null;
7066
+ this.el = this._createSnackbar();
6995
7067
  const root = Utils.portalRoot(this.options.root ?? document.body);
6996
7068
  if (!_Snackbar._container || !_Snackbar._container.isConnected || _Snackbar._container.parentNode !== root) {
6997
7069
  if (_Snackbar._container) _Snackbar._removeContainer();
6998
7070
  _Snackbar._createContainer(root);
6999
7071
  }
7072
+ _Snackbar._container.appendChild(this.el);
7073
+ this.el["Expressive_Snackbar"] = this;
7000
7074
  _Snackbar._snackbars.push(this);
7001
- const snackbarElement = this._createSnackbar();
7002
- snackbarElement["Expressive_Snackbar"] = this;
7003
- this.el = snackbarElement;
7004
7075
  this._animateIn();
7005
7076
  this._setTimer();
7006
7077
  }
@@ -7042,6 +7113,7 @@ var Expressive = (() => {
7042
7113
  snackbar.el.style.transition = "";
7043
7114
  _Snackbar._dragPointerId = e.pointerId;
7044
7115
  snackbar.startingXPos = e.clientX;
7116
+ snackbar.velocityX = 0;
7045
7117
  snackbar.time = Date.now();
7046
7118
  snackbar.xPos = e.clientX;
7047
7119
  }
@@ -7070,7 +7142,8 @@ var Expressive = (() => {
7070
7142
  snackbar.el.classList.remove("panning");
7071
7143
  const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
7072
7144
  const activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
7073
- const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || snackbar.velocityX > 1;
7145
+ const velocity = Date.now() - snackbar.time < 100 ? snackbar.velocityX : 0;
7146
+ const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || velocity > 1;
7074
7147
  if (shouldBeDismissed) {
7075
7148
  snackbar.wasSwiped = true;
7076
7149
  snackbar.dismiss();
@@ -7114,7 +7187,23 @@ var Expressive = (() => {
7114
7187
  if (snackbar instanceof HTMLTemplateElement) {
7115
7188
  const node = snackbar.content.cloneNode(true);
7116
7189
  snackbar = node.firstElementChild;
7190
+ } else if (snackbar && this.options.snackbarId) {
7191
+ const placeholder = document.createComment("");
7192
+ snackbar.before(placeholder);
7193
+ const children = [...snackbar.childNodes];
7194
+ const attributes = ["class", "style", "role", "aria-live", "aria-atomic", "inert"].map((name) => [name, snackbar.getAttribute(name)]);
7195
+ this._restoreElement = () => {
7196
+ snackbar.replaceChildren(...children);
7197
+ for (const [name, value] of attributes) {
7198
+ if (value === null) snackbar.removeAttribute(name);
7199
+ else snackbar.setAttribute(name, value);
7200
+ }
7201
+ placeholder.replaceWith(snackbar);
7202
+ };
7117
7203
  }
7204
+ if (!snackbar) throw new Error("Snackbar body not found");
7205
+ this._events = new (snackbar.ownerDocument.defaultView ?? window).AbortController();
7206
+ const listenerOptions = { signal: this._events.signal };
7118
7207
  snackbar.classList.add("snackbar");
7119
7208
  snackbar.setAttribute("role", "status");
7120
7209
  snackbar.setAttribute("aria-live", "polite");
@@ -7125,16 +7214,19 @@ var Expressive = (() => {
7125
7214
  this._returnFocus = e.relatedTarget;
7126
7215
  }
7127
7216
  this._pauseTimer();
7128
- });
7217
+ }, listenerOptions);
7129
7218
  snackbar.addEventListener("keydown", (e) => {
7130
7219
  if (e.key !== "Escape" || e.defaultPrevented || this._dismissed) return;
7131
7220
  e.preventDefault();
7132
7221
  e.stopPropagation();
7133
7222
  this.dismiss();
7134
- });
7135
- snackbar.addEventListener("focusout", () => setTimeout(() => this._resumeTimer(), 0));
7136
- snackbar.addEventListener("pointerenter", () => this._pauseTimer());
7137
- snackbar.addEventListener("pointerleave", () => this._resumeTimer());
7223
+ }, listenerOptions);
7224
+ snackbar.addEventListener("focusout", () => {
7225
+ clearTimeout(this._focusTimer);
7226
+ this._focusTimer = setTimeout(() => this._resumeTimer(), 0);
7227
+ }, listenerOptions);
7228
+ snackbar.addEventListener("pointerenter", () => this._pauseTimer(), listenerOptions);
7229
+ snackbar.addEventListener("pointerleave", () => this._resumeTimer(), listenerOptions);
7138
7230
  if (this.options.classes.length > 0) {
7139
7231
  snackbar.classList.add(...this.options.classes.split(" ").filter(Boolean));
7140
7232
  }
@@ -7155,7 +7247,7 @@ var Expressive = (() => {
7155
7247
  } finally {
7156
7248
  this.dismiss();
7157
7249
  }
7158
- });
7250
+ }, listenerOptions);
7159
7251
  snackbar.appendChild(action);
7160
7252
  }
7161
7253
  if (this.options.dismissible) {
@@ -7171,12 +7263,32 @@ var Expressive = (() => {
7171
7263
  close.addEventListener("click", (e) => {
7172
7264
  e.stopPropagation();
7173
7265
  this.dismiss();
7174
- });
7266
+ }, listenerOptions);
7175
7267
  snackbar.appendChild(close);
7176
7268
  }
7177
- _Snackbar._container.appendChild(snackbar);
7178
7269
  return snackbar;
7179
7270
  }
7271
+ _remove() {
7272
+ if (this._events.signal.aborted) return;
7273
+ this._events.abort();
7274
+ clearTimeout(this.counterTimeout);
7275
+ clearTimeout(this._transitionTimer);
7276
+ clearTimeout(this._dismissTimer);
7277
+ clearTimeout(this._focusTimer);
7278
+ this.counterTimeout = null;
7279
+ if (_Snackbar._draggedSnackbar === this) {
7280
+ _Snackbar._draggedSnackbar = null;
7281
+ _Snackbar._dragPointerId = null;
7282
+ }
7283
+ this.el["Expressive_Snackbar"] = void 0;
7284
+ if (this._restoreElement) this._restoreElement();
7285
+ else this.el.remove();
7286
+ const index = _Snackbar._snackbars.indexOf(this);
7287
+ if (index >= 0) _Snackbar._snackbars.splice(index, 1);
7288
+ if (!_Snackbar._snackbars.length && _Snackbar._container?.childElementCount === 0) {
7289
+ _Snackbar._removeContainer();
7290
+ }
7291
+ }
7180
7292
  _animateIn() {
7181
7293
  this.el.style.display = "";
7182
7294
  this.el.style.opacity = "0";
@@ -7185,7 +7297,7 @@ var Expressive = (() => {
7185
7297
  transform ${this.options.inDuration}ms ease,
7186
7298
  opacity ${this.options.inDuration}ms ease
7187
7299
  `;
7188
- setTimeout(() => {
7300
+ this._transitionTimer = setTimeout(() => {
7189
7301
  this.el.style.transform = "";
7190
7302
  this.el.style.opacity = "1";
7191
7303
  }, 1);
@@ -7214,12 +7326,12 @@ var Expressive = (() => {
7214
7326
  if (this._dismissed || this.panning || this.el.matches(":hover, :focus-within") || this.counterTimeout != null) return;
7215
7327
  this._setTimer();
7216
7328
  }
7217
- _restoreFocus() {
7329
+ _restoreFocus(remove = false) {
7218
7330
  const focused = this.el.getRootNode().activeElement;
7219
- if (focused && this.el.contains(focused) && this._returnFocus?.isConnected) {
7220
- this._returnFocus.focus({ preventScroll: true });
7221
- }
7331
+ const returnFocus = focused && this.el.contains(focused) ? this._returnFocus : null;
7222
7332
  this.el.inert = true;
7333
+ if (remove) this._remove();
7334
+ if (returnFocus?.isConnected) returnFocus.focus({ preventScroll: true });
7223
7335
  }
7224
7336
  /**
7225
7337
  * Dismiss snackbar with animation.
@@ -7230,6 +7342,7 @@ var Expressive = (() => {
7230
7342
  clearTimeout(this.counterTimeout);
7231
7343
  this.counterTimeout = null;
7232
7344
  this._restoreFocus();
7345
+ if (this._events.signal.aborted) return;
7233
7346
  const activationDistance = this.el.offsetWidth * this.options.activationPercent;
7234
7347
  if (this.wasSwiped) {
7235
7348
  this.el.style.transition = "transform .05s, opacity .05s";
@@ -7239,22 +7352,16 @@ var Expressive = (() => {
7239
7352
  this.el.style.transition = `
7240
7353
  margin ${this.options.outDuration}ms ease,
7241
7354
  opacity ${this.options.outDuration}ms ease`;
7242
- setTimeout(() => {
7355
+ clearTimeout(this._transitionTimer);
7356
+ this._transitionTimer = setTimeout(() => {
7243
7357
  this.el.style.opacity = "0";
7244
7358
  this.el.style.marginTop = "-40px";
7245
7359
  }, 1);
7246
- setTimeout(() => {
7360
+ this._dismissTimer = setTimeout(() => {
7361
+ this._remove();
7247
7362
  if (typeof this.options.completeCallback === "function") {
7248
7363
  this.options.completeCallback();
7249
7364
  }
7250
- if (this.el.id != this.options.snackbarId) {
7251
- this.el.remove();
7252
- const index = _Snackbar._snackbars.indexOf(this);
7253
- if (index >= 0) _Snackbar._snackbars.splice(index, 1);
7254
- if (_Snackbar._snackbars.length === 0 && _Snackbar._container && _Snackbar._container.childElementCount === 0) {
7255
- _Snackbar._removeContainer();
7256
- }
7257
- }
7258
7365
  }, this.options.outDuration);
7259
7366
  }
7260
7367
  };
@@ -7283,9 +7390,8 @@ var Expressive = (() => {
7283
7390
  /**
7284
7391
  * Show tooltip.
7285
7392
  */
7286
- this.open = (isManual) => {
7393
+ this.open = (isManual = true) => {
7287
7394
  if (this.isOpen) return;
7288
- isManual = isManual === void 0 ? true : void 0;
7289
7395
  clearTimeout(this._exitDelayTimeout);
7290
7396
  clearTimeout(this._animationTimeout);
7291
7397
  this.isOpen = true;
@@ -7369,8 +7475,21 @@ var Expressive = (() => {
7369
7475
  this.isOpen = false;
7370
7476
  this.isHovered = false;
7371
7477
  this.isFocused = false;
7372
- if (this.el.getAttribute("aria-describedby") === this.tooltipEl.id) {
7373
- this.el.removeAttribute("aria-describedby");
7478
+ const descriptions = this.el.getAttribute("aria-describedby")?.split(/\s+/);
7479
+ if (descriptions?.includes(this.tooltipEl.id)) {
7480
+ const remaining = descriptions.filter((id) => id && id !== this.tooltipEl.id).join(" ");
7481
+ if (remaining) this.el.setAttribute("aria-describedby", remaining);
7482
+ else this.el.removeAttribute("aria-describedby");
7483
+ }
7484
+ if (this._originalContent) {
7485
+ const { el, marker, display, priority, hidden, contentClass } = this._originalContent;
7486
+ el.style.setProperty("display", display, priority);
7487
+ if (hidden === null) el.removeAttribute("hidden");
7488
+ else el.setAttribute("hidden", hidden);
7489
+ el.classList.toggle("tooltip-content", contentClass);
7490
+ if (!el.className) el.removeAttribute("class");
7491
+ marker.replaceWith(el);
7492
+ this._originalContent = null;
7374
7493
  }
7375
7494
  this.tooltipEl.remove();
7376
7495
  this._removeEventHandlers();
@@ -7381,10 +7500,21 @@ var Expressive = (() => {
7381
7500
  this.tooltipEl.classList.add("tooltip");
7382
7501
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
7383
7502
  this.tooltipEl.setAttribute("role", "tooltip");
7384
- this.el.setAttribute("aria-describedby", this.tooltipEl.id);
7503
+ this.el.setAttribute("aria-describedby", [this.el.getAttribute("aria-describedby"), this.tooltipEl.id].filter(Boolean).join(" "));
7385
7504
  const tooltipContentEl = this.options.tooltipId ? Utils.getElementById(this.el, this.options.tooltipId) : document.createElement("div");
7386
7505
  if (this.options.tooltipId) {
7387
7506
  this.tooltipEl.classList.add("rich");
7507
+ const marker = document.createComment("");
7508
+ tooltipContentEl.before(marker);
7509
+ this._originalContent = {
7510
+ el: tooltipContentEl,
7511
+ marker,
7512
+ display: tooltipContentEl.style.display,
7513
+ priority: tooltipContentEl.style.getPropertyPriority("display"),
7514
+ hidden: tooltipContentEl.getAttribute("hidden"),
7515
+ contentClass: tooltipContentEl.classList.contains("tooltip-content")
7516
+ };
7517
+ tooltipContentEl.removeAttribute("hidden");
7388
7518
  }
7389
7519
  tooltipContentEl.style.display = "";
7390
7520
  tooltipContentEl.classList.add("tooltip-content");
@@ -7582,7 +7712,7 @@ var Expressive = (() => {
7582
7712
  }
7583
7713
 
7584
7714
  // src/ts/modular.ts
7585
- var version = "0.11.0";
7715
+ var version = "0.12.0";
7586
7716
 
7587
7717
  // src/ts/index.ts
7588
7718
  Forms.Init();