@y14e/menu 1.4.5 → 1.4.7

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,14 +10,16 @@ npm i @y14e/menu
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import Menu from '@y14e/menu@1.4.5';
13
+ import Menu from '@y14e/menu@1.4.7';
14
+ // with middleware
15
+ import Menu, { flip, offset, shift } from '@y14e/menu@1.4.7';
14
16
 
15
17
  // CDNs
16
- import Menu from 'https://esm.sh/@y14e/menu@1.4.5';
18
+ import Menu from 'https://esm.sh/@y14e/menu@1.4.7';
17
19
  // or
18
- import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.4.5/+esm';
20
+ import Menu from 'https://cdn.jsdelivr.net/npm/@y14e/menu@1.4.7/+esm';
19
21
  // or
20
- import Menu from 'https://esm.unpkg.com/@y14e/menu@1.4.5';
22
+ import Menu from 'https://esm.unpkg.com/@y14e/menu@1.4.7';
21
23
  ```
22
24
 
23
25
  ## Usage
package/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  // node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
4
6
  var min = Math.min;
5
7
  var max = Math.max;
@@ -2621,8 +2623,9 @@ var Menu = class _Menu {
2621
2623
  }
2622
2624
  };
2623
2625
  #settings;
2624
- #isSubmenu;
2626
+ #externalTrigger;
2625
2627
  #isPortal;
2628
+ #isSubmenu;
2626
2629
  #triggerElement;
2627
2630
  #listElement;
2628
2631
  #itemElements;
@@ -2651,9 +2654,14 @@ var Menu = class _Menu {
2651
2654
  this.#defaults = this.#mergeOptions(this.#defaults, _Menu.defaults);
2652
2655
  this.#settings = this.#mergeOptions(this.#defaults, options);
2653
2656
  matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
2654
- const { isSubmenu = false, isPortal = false } = _internal;
2655
- this.#isSubmenu = isSubmenu;
2657
+ const {
2658
+ externalTrigger = null,
2659
+ isPortal = false,
2660
+ isSubmenu = false
2661
+ } = _internal;
2662
+ this.#externalTrigger = externalTrigger;
2656
2663
  this.#isPortal = isPortal;
2664
+ this.#isSubmenu = isSubmenu;
2657
2665
  const { selector } = this.#settings;
2658
2666
  this.#triggerElement = this.#rootElement.querySelector(
2659
2667
  selector[this.#isSubmenu ? "item" : "trigger"]
@@ -2741,6 +2749,7 @@ var Menu = class _Menu {
2741
2749
  }
2742
2750
  this.#animation?.cancel();
2743
2751
  this.#animation = null;
2752
+ this.#externalTrigger = null;
2744
2753
  const elements = this.#itemElements;
2745
2754
  if (this.#triggerElement) {
2746
2755
  elements.push(this.#triggerElement);
@@ -2831,8 +2840,8 @@ var Menu = class _Menu {
2831
2840
  if (parent?.querySelector(this.#settings.selector.list)) {
2832
2841
  this.#submenus.push(
2833
2842
  new _Menu(parent, this.#settings, {
2834
- isSubmenu: true,
2835
- isPortal: !!this.#triggerElement
2843
+ isPortal: !!this.#triggerElement,
2844
+ isSubmenu: true
2836
2845
  })
2837
2846
  );
2838
2847
  } else if (item2.hasAttribute("disabled") || item2.tabIndex < 0) {
@@ -2916,7 +2925,7 @@ var Menu = class _Menu {
2916
2925
  }
2917
2926
  if (shiftKey && key === "Tab") {
2918
2927
  this.close();
2919
- requestAnimationFrame(() => this.#triggerElement?.focus());
2928
+ requestAnimationFrame(() => this.#focusTrigger());
2920
2929
  return;
2921
2930
  }
2922
2931
  if (![
@@ -2990,7 +2999,7 @@ var Menu = class _Menu {
2990
2999
  if (!this.#listElement) {
2991
3000
  return;
2992
3001
  }
2993
- if (!this.#isSubmenu && this.#triggerElement || !this.#isPortal) {
3002
+ if (!this.#isPortal || !this.#isSubmenu && this.#triggerElement) {
2994
3003
  const style2 = this.#listElement.style;
2995
3004
  style2.setProperty("position", "fixed");
2996
3005
  this.#cleanupPortal = createPortal(this.#listElement);
@@ -3006,11 +3015,7 @@ var Menu = class _Menu {
3006
3015
  this.#itemElements.filter(isFocusable3).at(isFocusLastItem ? -1 : 0)?.focus();
3007
3016
  } else {
3008
3017
  this.#clearSubmenuTimer();
3009
- const active = getActiveElement4();
3010
- if (!(active instanceof HTMLElement)) {
3011
- return;
3012
- }
3013
- this.#triggerElement && this.#containsRoot(active) && this.#triggerElement.focus();
3018
+ this.#focusTrigger();
3014
3019
  }
3015
3020
  if (!this.#triggerElement) {
3016
3021
  return;
@@ -3075,6 +3080,14 @@ var Menu = class _Menu {
3075
3080
  #containsRoot(element) {
3076
3081
  return this.#rootElement.contains(element) || this.#listElement?.contains(element);
3077
3082
  }
3083
+ #focusTrigger() {
3084
+ const active = getActiveElement4();
3085
+ if (!(active instanceof HTMLElement)) {
3086
+ return;
3087
+ }
3088
+ const trigger = this.#externalTrigger ?? this.#triggerElement;
3089
+ this.#containsRoot(active) && trigger && trigger.tabIndex >= 0 && trigger.focus();
3090
+ }
3078
3091
  #includesRoot(event) {
3079
3092
  const path = event.composedPath();
3080
3093
  if (!this.#listElement) {
@@ -3229,7 +3242,7 @@ function isFocusable3(element) {
3229
3242
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3230
3243
  * Supports checkbox item, radio item, and infinitely nested menus.
3231
3244
  *
3232
- * @version 1.4.5
3245
+ * @version 1.4.7
3233
3246
  * @author Yusuke Kamiyamane
3234
3247
  * @license MIT
3235
3248
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -3338,4 +3351,7 @@ function isFocusable3(element) {
3338
3351
  *)
3339
3352
  */
3340
3353
 
3341
- module.exports = Menu;
3354
+ exports.default = Menu;
3355
+ exports.flip = flip2;
3356
+ exports.offset = offset2;
3357
+ exports.shift = shift2;
package/dist/index.d.cts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { Middleware, Placement } from '@floating-ui/dom';
2
+ export { flip, offset, shift } from '@floating-ui/dom';
2
3
 
3
4
  /**
4
5
  * Menu
5
6
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
6
7
  * Supports checkbox item, radio item, and infinitely nested menus.
7
8
  *
8
- * @version 1.4.5
9
+ * @version 1.4.7
9
10
  * @author Yusuke Kamiyamane
10
11
  * @license MIT
11
12
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -37,8 +38,9 @@ interface MenuPopoverOptions {
37
38
  readonly placement?: Placement | string;
38
39
  }
39
40
  interface InternalOptions {
40
- readonly isSubmenu?: boolean;
41
+ readonly externalTrigger?: HTMLElement;
41
42
  readonly isPortal?: boolean;
43
+ readonly isSubmenu?: boolean;
42
44
  }
43
45
  declare class Menu {
44
46
  #private;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { Middleware, Placement } from '@floating-ui/dom';
2
+ export { flip, offset, shift } from '@floating-ui/dom';
2
3
 
3
4
  /**
4
5
  * Menu
5
6
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
6
7
  * Supports checkbox item, radio item, and infinitely nested menus.
7
8
  *
8
- * @version 1.4.5
9
+ * @version 1.4.7
9
10
  * @author Yusuke Kamiyamane
10
11
  * @license MIT
11
12
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -37,8 +38,9 @@ interface MenuPopoverOptions {
37
38
  readonly placement?: Placement | string;
38
39
  }
39
40
  interface InternalOptions {
40
- readonly isSubmenu?: boolean;
41
+ readonly externalTrigger?: HTMLElement;
41
42
  readonly isPortal?: boolean;
43
+ readonly isSubmenu?: boolean;
42
44
  }
43
45
  declare class Menu {
44
46
  #private;
package/dist/index.js CHANGED
@@ -2619,8 +2619,9 @@ var Menu = class _Menu {
2619
2619
  }
2620
2620
  };
2621
2621
  #settings;
2622
- #isSubmenu;
2622
+ #externalTrigger;
2623
2623
  #isPortal;
2624
+ #isSubmenu;
2624
2625
  #triggerElement;
2625
2626
  #listElement;
2626
2627
  #itemElements;
@@ -2649,9 +2650,14 @@ var Menu = class _Menu {
2649
2650
  this.#defaults = this.#mergeOptions(this.#defaults, _Menu.defaults);
2650
2651
  this.#settings = this.#mergeOptions(this.#defaults, options);
2651
2652
  matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
2652
- const { isSubmenu = false, isPortal = false } = _internal;
2653
- this.#isSubmenu = isSubmenu;
2653
+ const {
2654
+ externalTrigger = null,
2655
+ isPortal = false,
2656
+ isSubmenu = false
2657
+ } = _internal;
2658
+ this.#externalTrigger = externalTrigger;
2654
2659
  this.#isPortal = isPortal;
2660
+ this.#isSubmenu = isSubmenu;
2655
2661
  const { selector } = this.#settings;
2656
2662
  this.#triggerElement = this.#rootElement.querySelector(
2657
2663
  selector[this.#isSubmenu ? "item" : "trigger"]
@@ -2739,6 +2745,7 @@ var Menu = class _Menu {
2739
2745
  }
2740
2746
  this.#animation?.cancel();
2741
2747
  this.#animation = null;
2748
+ this.#externalTrigger = null;
2742
2749
  const elements = this.#itemElements;
2743
2750
  if (this.#triggerElement) {
2744
2751
  elements.push(this.#triggerElement);
@@ -2829,8 +2836,8 @@ var Menu = class _Menu {
2829
2836
  if (parent?.querySelector(this.#settings.selector.list)) {
2830
2837
  this.#submenus.push(
2831
2838
  new _Menu(parent, this.#settings, {
2832
- isSubmenu: true,
2833
- isPortal: !!this.#triggerElement
2839
+ isPortal: !!this.#triggerElement,
2840
+ isSubmenu: true
2834
2841
  })
2835
2842
  );
2836
2843
  } else if (item2.hasAttribute("disabled") || item2.tabIndex < 0) {
@@ -2914,7 +2921,7 @@ var Menu = class _Menu {
2914
2921
  }
2915
2922
  if (shiftKey && key === "Tab") {
2916
2923
  this.close();
2917
- requestAnimationFrame(() => this.#triggerElement?.focus());
2924
+ requestAnimationFrame(() => this.#focusTrigger());
2918
2925
  return;
2919
2926
  }
2920
2927
  if (![
@@ -2988,7 +2995,7 @@ var Menu = class _Menu {
2988
2995
  if (!this.#listElement) {
2989
2996
  return;
2990
2997
  }
2991
- if (!this.#isSubmenu && this.#triggerElement || !this.#isPortal) {
2998
+ if (!this.#isPortal || !this.#isSubmenu && this.#triggerElement) {
2992
2999
  const style2 = this.#listElement.style;
2993
3000
  style2.setProperty("position", "fixed");
2994
3001
  this.#cleanupPortal = createPortal(this.#listElement);
@@ -3004,11 +3011,7 @@ var Menu = class _Menu {
3004
3011
  this.#itemElements.filter(isFocusable3).at(isFocusLastItem ? -1 : 0)?.focus();
3005
3012
  } else {
3006
3013
  this.#clearSubmenuTimer();
3007
- const active = getActiveElement4();
3008
- if (!(active instanceof HTMLElement)) {
3009
- return;
3010
- }
3011
- this.#triggerElement && this.#containsRoot(active) && this.#triggerElement.focus();
3014
+ this.#focusTrigger();
3012
3015
  }
3013
3016
  if (!this.#triggerElement) {
3014
3017
  return;
@@ -3073,6 +3076,14 @@ var Menu = class _Menu {
3073
3076
  #containsRoot(element) {
3074
3077
  return this.#rootElement.contains(element) || this.#listElement?.contains(element);
3075
3078
  }
3079
+ #focusTrigger() {
3080
+ const active = getActiveElement4();
3081
+ if (!(active instanceof HTMLElement)) {
3082
+ return;
3083
+ }
3084
+ const trigger = this.#externalTrigger ?? this.#triggerElement;
3085
+ this.#containsRoot(active) && trigger && trigger.tabIndex >= 0 && trigger.focus();
3086
+ }
3076
3087
  #includesRoot(event) {
3077
3088
  const path = event.composedPath();
3078
3089
  if (!this.#listElement) {
@@ -3227,7 +3238,7 @@ function isFocusable3(element) {
3227
3238
  * WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript.
3228
3239
  * Supports checkbox item, radio item, and infinitely nested menus.
3229
3240
  *
3230
- * @version 1.4.5
3241
+ * @version 1.4.7
3231
3242
  * @author Yusuke Kamiyamane
3232
3243
  * @license MIT
3233
3244
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -3336,4 +3347,4 @@ function isFocusable3(element) {
3336
3347
  *)
3337
3348
  */
3338
3349
 
3339
- export { Menu as default };
3350
+ export { Menu as default, flip2 as flip, offset2 as offset, shift2 as shift };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/menu",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "WAI-ARIA compliant menu (menu button) pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",