@y14e/menu 1.5.2 → 1.5.3

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.
package/README.md CHANGED
@@ -10,16 +10,16 @@ npm i @y14e/menu
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import Menu from '@y14e/menu@1.5.2';
13
+ import Menu from '@y14e/menu@1.5.3';
14
14
  // with middleware
15
- import Menu, { flip, offset, shift } from '@y14e/menu@1.5.2';
15
+ import Menu, { flip, offset, shift } from '@y14e/menu@1.5.3';
16
16
 
17
17
  // CDNs
18
- import Menu from 'https://esm.sh/@y14e/menu@1.5.2';
18
+ import Menu from 'https://esm.sh/@y14e/menu@1.5.3';
19
19
  // or
20
- import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.5.2/+esm';
20
+ import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.5.3/+esm';
21
21
  // or
22
- import Menu from 'https://esm.unpkg.com/@y14e/menu@1.5.2';
22
+ import Menu from 'https://esm.unpkg.com/@y14e/menu@1.5.3';
23
23
  ```
24
24
 
25
25
  ## Usage
package/dist/index.cjs CHANGED
@@ -2635,14 +2635,14 @@ var Menu = class _Menu {
2635
2635
  #radioItemElementsByGroup = /* @__PURE__ */ new WeakMap();
2636
2636
  #arrowElement;
2637
2637
  #controller = null;
2638
+ #cleanupPopover = null;
2639
+ #cleanupPortal = null;
2640
+ #cleanupRovingTabIndex = null;
2638
2641
  #animation = null;
2642
+ #buttons = [];
2639
2643
  #submenus = [];
2640
2644
  #submenuTimer;
2641
2645
  #isDestroyed = false;
2642
- #cleanupPortal = null;
2643
- #cleanupRovingTabIndex = null;
2644
- #cleanupPopover = null;
2645
- #buttons = [];
2646
2646
  constructor(root, options = {}, _internal = {}) {
2647
2647
  if (!(root instanceof HTMLElement)) {
2648
2648
  throw new TypeError("Invalid root element");
@@ -2752,15 +2752,16 @@ var Menu = class _Menu {
2752
2752
  }
2753
2753
  this.#animation?.cancel();
2754
2754
  this.#animation = null;
2755
- this.#externalTrigger = null;
2755
+ const trigger = this.#getTrigger();
2756
2756
  const elements = this.#itemElements;
2757
- if (this.#triggerElement) {
2758
- elements.push(this.#triggerElement);
2757
+ if (trigger) {
2758
+ elements.push(trigger);
2759
2759
  }
2760
2760
  if (this.#listElement) {
2761
2761
  elements.push(this.#listElement);
2762
2762
  }
2763
2763
  restoreAttributes(elements);
2764
+ this.#externalTrigger = null;
2764
2765
  this.#triggerElement = null;
2765
2766
  this.#listElement = null;
2766
2767
  this.#itemElements.length = 0;
@@ -2786,9 +2787,10 @@ var Menu = class _Menu {
2786
2787
  return;
2787
2788
  }
2788
2789
  saveAttributes([this.#listElement], ["aria-labelledby", "id", "role"]);
2789
- if (this.#triggerElement) {
2790
+ const trigger = this.#getTrigger();
2791
+ if (trigger && this.#triggerElement) {
2790
2792
  saveAttributes(
2791
- [this.#triggerElement],
2793
+ [trigger],
2792
2794
  [
2793
2795
  "aria-controls",
2794
2796
  "aria-disabled",
@@ -2801,18 +2803,14 @@ var Menu = class _Menu {
2801
2803
  );
2802
2804
  const id = Math.random().toString(36).slice(-8);
2803
2805
  this.#listElement.id ||= `menu-list-${id}`;
2804
- addTokenToAttribute(
2805
- this.#triggerElement,
2806
- "aria-controls",
2807
- this.#listElement.id
2808
- );
2809
- this.#triggerElement.setAttribute("aria-expanded", "false");
2810
- this.#triggerElement.setAttribute("aria-haspopup", "true");
2811
- this.#triggerElement.id ||= `menu-trigger-${id}`;
2812
- if (!isFocusable3(this.#triggerElement)) {
2813
- this.#triggerElement.setAttribute("aria-disabled", "true");
2814
- this.#triggerElement.setAttribute("tabindex", "-1");
2815
- this.#triggerElement.style.setProperty("pointer-events", "none");
2806
+ addTokenToAttribute(trigger, "aria-controls", this.#listElement.id);
2807
+ trigger.setAttribute("aria-expanded", "false");
2808
+ trigger.setAttribute("aria-haspopup", "true");
2809
+ trigger.id ||= `menu-trigger-${id}`;
2810
+ if (!isFocusable3(trigger)) {
2811
+ trigger.setAttribute("aria-disabled", "true");
2812
+ trigger.setAttribute("tabindex", "-1");
2813
+ trigger.style.setProperty("pointer-events", "none");
2816
2814
  }
2817
2815
  this.#triggerElement.addEventListener("click", this.#onTriggerClick, {
2818
2816
  signal
@@ -2820,11 +2818,7 @@ var Menu = class _Menu {
2820
2818
  this.#triggerElement.addEventListener("keydown", this.#onTriggerKeyDown, {
2821
2819
  signal
2822
2820
  });
2823
- addTokenToAttribute(
2824
- this.#listElement,
2825
- "aria-labelledby",
2826
- this.#triggerElement.id
2827
- );
2821
+ addTokenToAttribute(this.#listElement, "aria-labelledby", trigger.id);
2828
2822
  this.#buttons.push(new Button(this.#triggerElement));
2829
2823
  }
2830
2824
  this.#listElement.setAttribute("role", "menu");
@@ -2907,7 +2901,7 @@ var Menu = class _Menu {
2907
2901
  #onTriggerClick = (event) => {
2908
2902
  event.preventDefault();
2909
2903
  this.#toggle(
2910
- this.#isSubmenu ? event.currentTarget === this.#triggerElement : this.#triggerElement?.ariaExpanded !== "true"
2904
+ this.#isSubmenu ? event.currentTarget === this.#triggerElement : this.#getTrigger()?.ariaExpanded !== "true"
2911
2905
  );
2912
2906
  };
2913
2907
  #onTriggerKeyDown = (event) => {
@@ -3001,10 +2995,11 @@ var Menu = class _Menu {
3001
2995
  });
3002
2996
  };
3003
2997
  #toggle(isOpen, options = {}) {
3004
- if (this.#triggerElement?.ariaExpanded === String(isOpen)) {
2998
+ const trigger = this.#getTrigger();
2999
+ if (trigger?.ariaExpanded === String(isOpen)) {
3005
3000
  return;
3006
3001
  }
3007
- this.#triggerElement?.setAttribute("aria-expanded", String(isOpen));
3002
+ trigger?.setAttribute("aria-expanded", String(isOpen));
3008
3003
  if (isOpen) {
3009
3004
  _Menu.#menus.filter((m) => !m.#containsRoot(this.#rootElement)).forEach((menu) => {
3010
3005
  menu.close();
@@ -3094,7 +3089,7 @@ var Menu = class _Menu {
3094
3089
  #closeAndMoveFocus(direction) {
3095
3090
  this.close();
3096
3091
  requestAnimationFrame(
3097
- () => (this.#externalTrigger ?? this.#triggerElement)?.dispatchEvent(
3092
+ () => this.#getTrigger()?.dispatchEvent(
3098
3093
  new KeyboardEvent("keydown", {
3099
3094
  key: direction === "previous" ? "ArrowLeft" : "ArrowRight"
3100
3095
  })
@@ -3109,7 +3104,10 @@ var Menu = class _Menu {
3109
3104
  if (!(active instanceof HTMLElement)) {
3110
3105
  return;
3111
3106
  }
3112
- this.#containsRoot(active) && (this.#externalTrigger ?? this.#triggerElement)?.focus();
3107
+ this.#containsRoot(active) && this.#getTrigger()?.focus();
3108
+ }
3109
+ #getTrigger() {
3110
+ return this.#externalTrigger ?? this.#triggerElement;
3113
3111
  }
3114
3112
  #includesRoot(event) {
3115
3113
  const path = event.composedPath();
@@ -3265,7 +3263,7 @@ function isFocusable3(element) {
3265
3263
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3266
3264
  * Supports checkbox item, radio item, and infinitely nested menus.
3267
3265
  *
3268
- * @version 1.5.2
3266
+ * @version 1.5.3
3269
3267
  * @author Yusuke Kamiyamane
3270
3268
  * @license MIT
3271
3269
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -6,7 +6,7 @@ export { flip, offset, shift } from '@floating-ui/dom';
6
6
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
7
7
  * Supports checkbox item, radio item, and infinitely nested menus.
8
8
  *
9
- * @version 1.5.2
9
+ * @version 1.5.3
10
10
  * @author Yusuke Kamiyamane
11
11
  * @license MIT
12
12
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { flip, offset, shift } from '@floating-ui/dom';
6
6
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
7
7
  * Supports checkbox item, radio item, and infinitely nested menus.
8
8
  *
9
- * @version 1.5.2
9
+ * @version 1.5.3
10
10
  * @author Yusuke Kamiyamane
11
11
  * @license MIT
12
12
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -2631,14 +2631,14 @@ var Menu = class _Menu {
2631
2631
  #radioItemElementsByGroup = /* @__PURE__ */ new WeakMap();
2632
2632
  #arrowElement;
2633
2633
  #controller = null;
2634
+ #cleanupPopover = null;
2635
+ #cleanupPortal = null;
2636
+ #cleanupRovingTabIndex = null;
2634
2637
  #animation = null;
2638
+ #buttons = [];
2635
2639
  #submenus = [];
2636
2640
  #submenuTimer;
2637
2641
  #isDestroyed = false;
2638
- #cleanupPortal = null;
2639
- #cleanupRovingTabIndex = null;
2640
- #cleanupPopover = null;
2641
- #buttons = [];
2642
2642
  constructor(root, options = {}, _internal = {}) {
2643
2643
  if (!(root instanceof HTMLElement)) {
2644
2644
  throw new TypeError("Invalid root element");
@@ -2748,15 +2748,16 @@ var Menu = class _Menu {
2748
2748
  }
2749
2749
  this.#animation?.cancel();
2750
2750
  this.#animation = null;
2751
- this.#externalTrigger = null;
2751
+ const trigger = this.#getTrigger();
2752
2752
  const elements = this.#itemElements;
2753
- if (this.#triggerElement) {
2754
- elements.push(this.#triggerElement);
2753
+ if (trigger) {
2754
+ elements.push(trigger);
2755
2755
  }
2756
2756
  if (this.#listElement) {
2757
2757
  elements.push(this.#listElement);
2758
2758
  }
2759
2759
  restoreAttributes(elements);
2760
+ this.#externalTrigger = null;
2760
2761
  this.#triggerElement = null;
2761
2762
  this.#listElement = null;
2762
2763
  this.#itemElements.length = 0;
@@ -2782,9 +2783,10 @@ var Menu = class _Menu {
2782
2783
  return;
2783
2784
  }
2784
2785
  saveAttributes([this.#listElement], ["aria-labelledby", "id", "role"]);
2785
- if (this.#triggerElement) {
2786
+ const trigger = this.#getTrigger();
2787
+ if (trigger && this.#triggerElement) {
2786
2788
  saveAttributes(
2787
- [this.#triggerElement],
2789
+ [trigger],
2788
2790
  [
2789
2791
  "aria-controls",
2790
2792
  "aria-disabled",
@@ -2797,18 +2799,14 @@ var Menu = class _Menu {
2797
2799
  );
2798
2800
  const id = Math.random().toString(36).slice(-8);
2799
2801
  this.#listElement.id ||= `menu-list-${id}`;
2800
- addTokenToAttribute(
2801
- this.#triggerElement,
2802
- "aria-controls",
2803
- this.#listElement.id
2804
- );
2805
- this.#triggerElement.setAttribute("aria-expanded", "false");
2806
- this.#triggerElement.setAttribute("aria-haspopup", "true");
2807
- this.#triggerElement.id ||= `menu-trigger-${id}`;
2808
- if (!isFocusable3(this.#triggerElement)) {
2809
- this.#triggerElement.setAttribute("aria-disabled", "true");
2810
- this.#triggerElement.setAttribute("tabindex", "-1");
2811
- this.#triggerElement.style.setProperty("pointer-events", "none");
2802
+ addTokenToAttribute(trigger, "aria-controls", this.#listElement.id);
2803
+ trigger.setAttribute("aria-expanded", "false");
2804
+ trigger.setAttribute("aria-haspopup", "true");
2805
+ trigger.id ||= `menu-trigger-${id}`;
2806
+ if (!isFocusable3(trigger)) {
2807
+ trigger.setAttribute("aria-disabled", "true");
2808
+ trigger.setAttribute("tabindex", "-1");
2809
+ trigger.style.setProperty("pointer-events", "none");
2812
2810
  }
2813
2811
  this.#triggerElement.addEventListener("click", this.#onTriggerClick, {
2814
2812
  signal
@@ -2816,11 +2814,7 @@ var Menu = class _Menu {
2816
2814
  this.#triggerElement.addEventListener("keydown", this.#onTriggerKeyDown, {
2817
2815
  signal
2818
2816
  });
2819
- addTokenToAttribute(
2820
- this.#listElement,
2821
- "aria-labelledby",
2822
- this.#triggerElement.id
2823
- );
2817
+ addTokenToAttribute(this.#listElement, "aria-labelledby", trigger.id);
2824
2818
  this.#buttons.push(new Button(this.#triggerElement));
2825
2819
  }
2826
2820
  this.#listElement.setAttribute("role", "menu");
@@ -2903,7 +2897,7 @@ var Menu = class _Menu {
2903
2897
  #onTriggerClick = (event) => {
2904
2898
  event.preventDefault();
2905
2899
  this.#toggle(
2906
- this.#isSubmenu ? event.currentTarget === this.#triggerElement : this.#triggerElement?.ariaExpanded !== "true"
2900
+ this.#isSubmenu ? event.currentTarget === this.#triggerElement : this.#getTrigger()?.ariaExpanded !== "true"
2907
2901
  );
2908
2902
  };
2909
2903
  #onTriggerKeyDown = (event) => {
@@ -2997,10 +2991,11 @@ var Menu = class _Menu {
2997
2991
  });
2998
2992
  };
2999
2993
  #toggle(isOpen, options = {}) {
3000
- if (this.#triggerElement?.ariaExpanded === String(isOpen)) {
2994
+ const trigger = this.#getTrigger();
2995
+ if (trigger?.ariaExpanded === String(isOpen)) {
3001
2996
  return;
3002
2997
  }
3003
- this.#triggerElement?.setAttribute("aria-expanded", String(isOpen));
2998
+ trigger?.setAttribute("aria-expanded", String(isOpen));
3004
2999
  if (isOpen) {
3005
3000
  _Menu.#menus.filter((m) => !m.#containsRoot(this.#rootElement)).forEach((menu) => {
3006
3001
  menu.close();
@@ -3090,7 +3085,7 @@ var Menu = class _Menu {
3090
3085
  #closeAndMoveFocus(direction) {
3091
3086
  this.close();
3092
3087
  requestAnimationFrame(
3093
- () => (this.#externalTrigger ?? this.#triggerElement)?.dispatchEvent(
3088
+ () => this.#getTrigger()?.dispatchEvent(
3094
3089
  new KeyboardEvent("keydown", {
3095
3090
  key: direction === "previous" ? "ArrowLeft" : "ArrowRight"
3096
3091
  })
@@ -3105,7 +3100,10 @@ var Menu = class _Menu {
3105
3100
  if (!(active instanceof HTMLElement)) {
3106
3101
  return;
3107
3102
  }
3108
- this.#containsRoot(active) && (this.#externalTrigger ?? this.#triggerElement)?.focus();
3103
+ this.#containsRoot(active) && this.#getTrigger()?.focus();
3104
+ }
3105
+ #getTrigger() {
3106
+ return this.#externalTrigger ?? this.#triggerElement;
3109
3107
  }
3110
3108
  #includesRoot(event) {
3111
3109
  const path = event.composedPath();
@@ -3261,7 +3259,7 @@ function isFocusable3(element) {
3261
3259
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3262
3260
  * Supports checkbox item, radio item, and infinitely nested menus.
3263
3261
  *
3264
- * @version 1.5.2
3262
+ * @version 1.5.3
3265
3263
  * @author Yusuke Kamiyamane
3266
3264
  * @license MIT
3267
3265
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/menu",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",