@y14e/menu 1.4.7 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.4.7';
13
+ import Menu from '@y14e/menu@1.5.0';
14
14
  // with middleware
15
- import Menu, { flip, offset, shift } from '@y14e/menu@1.4.7';
15
+ import Menu, { flip, offset, shift } from '@y14e/menu@1.5.0';
16
16
 
17
17
  // CDNs
18
- import Menu from 'https://esm.sh/@y14e/menu@1.4.7';
18
+ import Menu from 'https://esm.sh/@y14e/menu@1.5.0';
19
19
  // or
20
- import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.4.7/+esm';
20
+ import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.5.0/+esm';
21
21
  // or
22
- import Menu from 'https://esm.unpkg.com/@y14e/menu@1.4.7';
22
+ import Menu from 'https://esm.unpkg.com/@y14e/menu@1.5.0';
23
23
  ```
24
24
 
25
25
  ## Usage
package/dist/index.cjs CHANGED
@@ -2624,6 +2624,7 @@ var Menu = class _Menu {
2624
2624
  };
2625
2625
  #settings;
2626
2626
  #externalTrigger;
2627
+ #isMenubar;
2627
2628
  #isPortal;
2628
2629
  #isSubmenu;
2629
2630
  #triggerElement;
@@ -2656,10 +2657,12 @@ var Menu = class _Menu {
2656
2657
  matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
2657
2658
  const {
2658
2659
  externalTrigger = null,
2660
+ isMenubar = false,
2659
2661
  isPortal = false,
2660
2662
  isSubmenu = false
2661
2663
  } = _internal;
2662
2664
  this.#externalTrigger = externalTrigger;
2665
+ this.#isMenubar = isMenubar;
2663
2666
  this.#isPortal = isPortal;
2664
2667
  this.#isSubmenu = isSubmenu;
2665
2668
  const { selector } = this.#settings;
@@ -2932,7 +2935,8 @@ var Menu = class _Menu {
2932
2935
  "Enter",
2933
2936
  "Escape",
2934
2937
  " ",
2935
- ...this.#isSubmenu ? ["ArrowLeft"] : []
2938
+ "ArrowLeft",
2939
+ ...this.#isMenubar ? ["ArrowRight"] : []
2936
2940
  ].includes(key)) {
2937
2941
  return;
2938
2942
  }
@@ -2945,9 +2949,18 @@ var Menu = class _Menu {
2945
2949
  switch (key) {
2946
2950
  case "Tab":
2947
2951
  case "Escape":
2948
- case "ArrowLeft":
2949
2952
  this.close();
2950
2953
  return;
2954
+ case "ArrowLeft":
2955
+ if (this.#isMenubar) {
2956
+ this.#closeAndMoveFocus("previous");
2957
+ } else if (this.#isSubmenu && this.#triggerElement) {
2958
+ this.close();
2959
+ }
2960
+ return;
2961
+ case "ArrowRight":
2962
+ this.#closeAndMoveFocus("next");
2963
+ return;
2951
2964
  case "Enter":
2952
2965
  case " ":
2953
2966
  active.click();
@@ -3077,6 +3090,16 @@ var Menu = class _Menu {
3077
3090
  this.#submenuTimer = void 0;
3078
3091
  }
3079
3092
  }
3093
+ #closeAndMoveFocus(direction) {
3094
+ this.close();
3095
+ requestAnimationFrame(
3096
+ () => (this.#externalTrigger ?? this.#triggerElement)?.dispatchEvent(
3097
+ new KeyboardEvent("keydown", {
3098
+ key: direction === "previous" ? "ArrowLeft" : "ArrowRight"
3099
+ })
3100
+ )
3101
+ );
3102
+ }
3080
3103
  #containsRoot(element) {
3081
3104
  return this.#rootElement.contains(element) || this.#listElement?.contains(element);
3082
3105
  }
@@ -3085,8 +3108,7 @@ var Menu = class _Menu {
3085
3108
  if (!(active instanceof HTMLElement)) {
3086
3109
  return;
3087
3110
  }
3088
- const trigger = this.#externalTrigger ?? this.#triggerElement;
3089
- this.#containsRoot(active) && trigger && trigger.tabIndex >= 0 && trigger.focus();
3111
+ this.#containsRoot(active) && (this.#externalTrigger ?? this.#triggerElement)?.focus();
3090
3112
  }
3091
3113
  #includesRoot(event) {
3092
3114
  const path = event.composedPath();
@@ -3242,7 +3264,7 @@ function isFocusable3(element) {
3242
3264
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3243
3265
  * Supports checkbox item, radio item, and infinitely nested menus.
3244
3266
  *
3245
- * @version 1.4.7
3267
+ * @version 1.5.0
3246
3268
  * @author Yusuke Kamiyamane
3247
3269
  * @license MIT
3248
3270
  * @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.4.7
9
+ * @version 1.5.0
10
10
  * @author Yusuke Kamiyamane
11
11
  * @license MIT
12
12
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -39,6 +39,7 @@ interface MenuPopoverOptions {
39
39
  }
40
40
  interface InternalOptions {
41
41
  readonly externalTrigger?: HTMLElement;
42
+ readonly isMenubar?: boolean;
42
43
  readonly isPortal?: boolean;
43
44
  readonly isSubmenu?: boolean;
44
45
  }
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.4.7
9
+ * @version 1.5.0
10
10
  * @author Yusuke Kamiyamane
11
11
  * @license MIT
12
12
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -39,6 +39,7 @@ interface MenuPopoverOptions {
39
39
  }
40
40
  interface InternalOptions {
41
41
  readonly externalTrigger?: HTMLElement;
42
+ readonly isMenubar?: boolean;
42
43
  readonly isPortal?: boolean;
43
44
  readonly isSubmenu?: boolean;
44
45
  }
package/dist/index.js CHANGED
@@ -2620,6 +2620,7 @@ var Menu = class _Menu {
2620
2620
  };
2621
2621
  #settings;
2622
2622
  #externalTrigger;
2623
+ #isMenubar;
2623
2624
  #isPortal;
2624
2625
  #isSubmenu;
2625
2626
  #triggerElement;
@@ -2652,10 +2653,12 @@ var Menu = class _Menu {
2652
2653
  matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
2653
2654
  const {
2654
2655
  externalTrigger = null,
2656
+ isMenubar = false,
2655
2657
  isPortal = false,
2656
2658
  isSubmenu = false
2657
2659
  } = _internal;
2658
2660
  this.#externalTrigger = externalTrigger;
2661
+ this.#isMenubar = isMenubar;
2659
2662
  this.#isPortal = isPortal;
2660
2663
  this.#isSubmenu = isSubmenu;
2661
2664
  const { selector } = this.#settings;
@@ -2928,7 +2931,8 @@ var Menu = class _Menu {
2928
2931
  "Enter",
2929
2932
  "Escape",
2930
2933
  " ",
2931
- ...this.#isSubmenu ? ["ArrowLeft"] : []
2934
+ "ArrowLeft",
2935
+ ...this.#isMenubar ? ["ArrowRight"] : []
2932
2936
  ].includes(key)) {
2933
2937
  return;
2934
2938
  }
@@ -2941,9 +2945,18 @@ var Menu = class _Menu {
2941
2945
  switch (key) {
2942
2946
  case "Tab":
2943
2947
  case "Escape":
2944
- case "ArrowLeft":
2945
2948
  this.close();
2946
2949
  return;
2950
+ case "ArrowLeft":
2951
+ if (this.#isMenubar) {
2952
+ this.#closeAndMoveFocus("previous");
2953
+ } else if (this.#isSubmenu && this.#triggerElement) {
2954
+ this.close();
2955
+ }
2956
+ return;
2957
+ case "ArrowRight":
2958
+ this.#closeAndMoveFocus("next");
2959
+ return;
2947
2960
  case "Enter":
2948
2961
  case " ":
2949
2962
  active.click();
@@ -3073,6 +3086,16 @@ var Menu = class _Menu {
3073
3086
  this.#submenuTimer = void 0;
3074
3087
  }
3075
3088
  }
3089
+ #closeAndMoveFocus(direction) {
3090
+ this.close();
3091
+ requestAnimationFrame(
3092
+ () => (this.#externalTrigger ?? this.#triggerElement)?.dispatchEvent(
3093
+ new KeyboardEvent("keydown", {
3094
+ key: direction === "previous" ? "ArrowLeft" : "ArrowRight"
3095
+ })
3096
+ )
3097
+ );
3098
+ }
3076
3099
  #containsRoot(element) {
3077
3100
  return this.#rootElement.contains(element) || this.#listElement?.contains(element);
3078
3101
  }
@@ -3081,8 +3104,7 @@ var Menu = class _Menu {
3081
3104
  if (!(active instanceof HTMLElement)) {
3082
3105
  return;
3083
3106
  }
3084
- const trigger = this.#externalTrigger ?? this.#triggerElement;
3085
- this.#containsRoot(active) && trigger && trigger.tabIndex >= 0 && trigger.focus();
3107
+ this.#containsRoot(active) && (this.#externalTrigger ?? this.#triggerElement)?.focus();
3086
3108
  }
3087
3109
  #includesRoot(event) {
3088
3110
  const path = event.composedPath();
@@ -3238,7 +3260,7 @@ function isFocusable3(element) {
3238
3260
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3239
3261
  * Supports checkbox item, radio item, and infinitely nested menus.
3240
3262
  *
3241
- * @version 1.4.7
3263
+ * @version 1.5.0
3242
3264
  * @author Yusuke Kamiyamane
3243
3265
  * @license MIT
3244
3266
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/menu",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
4
4
  "description": "WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",