@ailuracode/alpine-menu 0.1.0 → 0.2.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
@@ -1,6 +1,6 @@
1
1
  # @ailuracode/alpine-menu
2
2
 
3
- Headless accessible menu store for Alpine.js — dropdowns, context menus, keyboard navigation, and roving tabindex. No markup or CSS included.
3
+ Headless accessible menu store for Alpine.js — dropdowns, context menus, keyboard navigation, and roving tabindex. **Only one menu open at a time by default.** No markup or CSS included.
4
4
 
5
5
  **[Full documentation →](../../docs/plugins/menu.md)**
6
6
 
@@ -22,9 +22,20 @@ Alpine.plugin(
22
22
  );
23
23
  ```
24
24
 
25
+ ## Exclusive mode
26
+
27
+ Opening a menu closes all others by default (`exclusive: true`). Pass `exclusive: false` to allow multiple open menus, or use per-menu `group` for menubar-style exclusivity:
28
+
29
+ ```js
30
+ menu({ exclusive: false });
31
+ $store.menu.register("file", { group: "menubar-1" });
32
+ $store.menu.register("edit", { group: "menubar-1" });
33
+ ```
34
+
25
35
  ## Store API
26
36
 
27
37
  ```js
38
+ $store.menu.register("user-menu", { onSelect: (id) => {} });
28
39
  $store.menu.open("user-menu");
29
40
  $store.menu.close("user-menu");
30
41
  $store.menu.toggle("user-menu");
package/dist/global.d.ts CHANGED
@@ -1,49 +1,29 @@
1
1
  /// <reference types="@types/alpinejs" />
2
2
 
3
- export type MenuOrientation = "horizontal" | "vertical";
4
-
5
- export interface MenuStore {
6
- instances: Record<string, import("./store.js").MenuInstance>;
7
- open(id: string): void;
8
- close(id: string): void;
9
- toggle(id: string): void;
10
- isOpen(id: string): boolean;
11
- activeItem(id: string): string | null;
12
- register(id: string, options?: import("./store.js").MenuInstanceOptions): void;
13
- unregister(id: string): void;
14
- registerItem(
15
- menuId: string,
16
- itemId: string,
17
- options?: import("./store.js").MenuItemOptions
18
- ): void;
19
- unregisterItem(menuId: string, itemId: string): void;
20
- bindMenu(menuId: string, container: HTMLElement | null): void;
21
- bindTrigger(menuId: string, trigger: HTMLElement | null): void;
22
- handleOutsideClick(menuId: string, event: MouseEvent): void;
23
- setActiveItem(menuId: string, itemId: string | null): void;
24
- selectItem(menuId: string, itemId: string): void;
25
- handleKeydown(menuId: string, event: KeyboardEvent): void;
26
- itemProps(menuId: string, itemId: string): Record<string, string | number | boolean | undefined>;
27
- menuProps(menuId: string): Record<string, string | boolean | undefined>;
28
- destroy(): void;
29
- }
3
+ export type {
4
+ MenuInstanceOptions,
5
+ MenuItemOptions,
6
+ MenuOrientation,
7
+ MenuStore,
8
+ } from "./store.js";
30
9
 
31
10
  export interface MenuPluginOptions {
11
+ exclusive?: boolean;
32
12
  onLockChange?: (locked: boolean) => void;
33
13
  }
34
14
 
35
15
  export function menuOptions<const T extends MenuPluginOptions>(options: T): T;
36
- export function createMenuStore(config?: { onLockChange?: (locked: boolean) => void }): MenuStore;
16
+ export function createMenuStore(config?: MenuPluginOptions): import("./store.js").MenuStore;
37
17
 
38
18
  export default function menuPlugin(options?: MenuPluginOptions): import("alpinejs").PluginCallback;
39
19
 
40
20
  declare global {
41
21
  namespace Alpine {
42
22
  interface Stores {
43
- menu: MenuStore;
23
+ menu: import("./store.js").MenuStore;
44
24
  }
45
25
  interface Magics<T> {
46
- $menu: MenuStore;
26
+ $menu: import("./store.js").MenuStore;
47
27
  }
48
28
  }
49
29
  }
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ type MenuInstance = {
11
11
  activeItemId: string | null;
12
12
  orientation: MenuOrientation;
13
13
  closeOnSelect: boolean;
14
+ group: string | null;
14
15
  items: MenuItemState[];
15
16
  container: HTMLElement | null;
16
17
  trigger: HTMLElement | null;
@@ -25,6 +26,8 @@ type MenuItemOptions = {
25
26
  type MenuInstanceOptions = {
26
27
  orientation?: MenuOrientation;
27
28
  closeOnSelect?: boolean;
29
+ /** When store `exclusive` is `false`, only one menu per group may be open at a time. */
30
+ group?: string;
28
31
  onOpen?: () => void;
29
32
  onClose?: () => void;
30
33
  onSelect?: (itemId: string) => void;
@@ -47,17 +50,25 @@ type MenuStore = {
47
50
  setActiveItem(menuId: string, itemId: string | null): void;
48
51
  selectItem(menuId: string, itemId: string): void;
49
52
  handleKeydown(menuId: string, event: KeyboardEvent): void;
53
+ /** Close open menus on outside click — pass `menuIds` when wiring multiple menus on one page. */
54
+ handleWindowOutsideClick(event: MouseEvent, menuIds?: readonly string[]): void;
55
+ /** Route keyboard events to the first open menu in `menuIds` (defaults to all registered). */
56
+ handleWindowKeydown(event: KeyboardEvent, menuIds?: readonly string[]): void;
50
57
  itemProps(menuId: string, itemId: string): Record<string, string | number | boolean | undefined>;
51
58
  menuProps(menuId: string): Record<string, string | boolean | undefined>;
52
59
  destroy(): void;
53
60
  };
54
61
  type MenuStoreConfig = {
62
+ /** When true (default), opening a menu closes all other open menus. */
63
+ exclusive?: boolean;
55
64
  onLockChange?: (locked: boolean) => void;
56
65
  };
57
66
  /** Creates the headless menu store. */
58
67
  declare function createMenuStore(config?: MenuStoreConfig): MenuStore;
59
68
 
60
69
  interface MenuPluginOptions {
70
+ /** When true (default), opening a menu closes all other open menus. */
71
+ exclusive?: boolean;
61
72
  onLockChange?: (locked: boolean) => void;
62
73
  }
63
74
  /** Builds typed menu plugin options. */
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ function createInstance(options = {}) {
27
27
  activeItemId: null,
28
28
  orientation: options.orientation ?? "vertical",
29
29
  closeOnSelect: options.closeOnSelect ?? true,
30
+ group: options.group ?? null,
30
31
  items: [],
31
32
  container: null,
32
33
  trigger: null,
@@ -89,6 +90,7 @@ function handleMenuKeydown(menuId, instance, event, selectItem, close) {
89
90
  }
90
91
  }
91
92
  function createMenuStore(config = {}) {
93
+ const exclusive = config.exclusive ?? true;
92
94
  let lockCount = 0;
93
95
  function setLock(locked) {
94
96
  if (locked) {
@@ -110,6 +112,34 @@ function createMenuStore(config = {}) {
110
112
  store2.instances[id] ??= createInstance();
111
113
  return store2.instances[id];
112
114
  }
115
+ function closeMenu(menuStore, id, suppressLock = false) {
116
+ const instance = menuStore.instances[id];
117
+ if (!instance?.open) {
118
+ return;
119
+ }
120
+ instance.open = false;
121
+ if (!suppressLock) {
122
+ setLock(false);
123
+ }
124
+ instance.onClose?.();
125
+ }
126
+ function closeOtherMenus(menuStore, openingId) {
127
+ const opening = menuStore.instances[openingId];
128
+ const openingGroup = opening?.group ?? null;
129
+ let closedCount = 0;
130
+ for (const menuId of Object.keys(menuStore.instances)) {
131
+ if (menuId === openingId || !menuStore.isOpen(menuId)) {
132
+ continue;
133
+ }
134
+ const other = menuStore.instances[menuId];
135
+ const shouldClose = exclusive !== false || openingGroup !== null && other.group === openingGroup;
136
+ if (shouldClose) {
137
+ closeMenu(menuStore, menuId, true);
138
+ closedCount++;
139
+ }
140
+ }
141
+ return closedCount;
142
+ }
113
143
  const store = {
114
144
  instances: {},
115
145
  register(id, options = {}) {
@@ -150,22 +180,19 @@ function createMenuStore(config = {}) {
150
180
  if (instance.open) {
151
181
  return;
152
182
  }
183
+ const closedCount = closeOtherMenus(this, id);
153
184
  instance.open = true;
154
185
  if (!instance.activeItemId) {
155
186
  instance.activeItemId = firstItem(instance);
156
187
  }
157
- setLock(true);
188
+ if (closedCount === 0) {
189
+ setLock(true);
190
+ }
158
191
  instance.onOpen?.();
159
192
  queueMicrotask(() => focusActiveMenu(instance));
160
193
  },
161
194
  close(id) {
162
- const instance = this.instances[id];
163
- if (!instance?.open) {
164
- return;
165
- }
166
- instance.open = false;
167
- setLock(false);
168
- instance.onClose?.();
195
+ closeMenu(this, id);
169
196
  },
170
197
  toggle(id) {
171
198
  if (this.isOpen(id)) {
@@ -241,6 +268,21 @@ function createMenuStore(config = {}) {
241
268
  queueMicrotask(() => focusActiveMenu(instance));
242
269
  }
243
270
  },
271
+ handleWindowOutsideClick(event, menuIds) {
272
+ const ids = menuIds ?? Object.keys(this.instances);
273
+ for (const menuId of ids) {
274
+ this.handleOutsideClick(menuId, event);
275
+ }
276
+ },
277
+ handleWindowKeydown(event, menuIds) {
278
+ const ids = menuIds ?? Object.keys(this.instances);
279
+ for (const menuId of ids) {
280
+ if (this.isOpen(menuId)) {
281
+ this.handleKeydown(menuId, event);
282
+ return;
283
+ }
284
+ }
285
+ },
244
286
  itemProps(menuId, itemId) {
245
287
  const instance = this.instances[menuId];
246
288
  const item = instance?.items.find((entry) => entry.id === itemId);
@@ -276,6 +318,7 @@ function menuOptions(options) {
276
318
  function menuPlugin(options = {}) {
277
319
  return function registerMenu(Alpine) {
278
320
  const store = createMenuStore({
321
+ exclusive: options.exclusive,
279
322
  onLockChange: options.onLockChange
280
323
  });
281
324
  Alpine.store("menu", store);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store.ts","../src/index.ts"],"sourcesContent":["export type MenuOrientation = \"vertical\" | \"horizontal\";\n\nexport type MenuItemState = {\n id: string;\n disabled: boolean;\n parentId: string | null;\n};\n\nexport type MenuInstance = {\n open: boolean;\n activeItemId: string | null;\n orientation: MenuOrientation;\n closeOnSelect: boolean;\n items: MenuItemState[];\n container: HTMLElement | null;\n trigger: HTMLElement | null;\n onOpen?: () => void;\n onClose?: () => void;\n onSelect?: (itemId: string) => void;\n};\n\nexport type MenuItemOptions = {\n disabled?: boolean;\n parentId?: string | null;\n};\n\nexport type MenuInstanceOptions = {\n orientation?: MenuOrientation;\n closeOnSelect?: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n onSelect?: (itemId: string) => void;\n};\n\nexport type MenuStore = {\n /** Reactive registry of menu instances. */\n instances: Record<string, MenuInstance>;\n open(id: string): void;\n close(id: string): void;\n toggle(id: string): void;\n isOpen(id: string): boolean;\n activeItem(id: string): string | null;\n register(id: string, options?: MenuInstanceOptions): void;\n unregister(id: string): void;\n registerItem(menuId: string, itemId: string, options?: MenuItemOptions): void;\n unregisterItem(menuId: string, itemId: string): void;\n bindMenu(menuId: string, container: HTMLElement | null): void;\n bindTrigger(menuId: string, trigger: HTMLElement | null): void;\n handleOutsideClick(menuId: string, event: MouseEvent): void;\n setActiveItem(menuId: string, itemId: string | null): void;\n selectItem(menuId: string, itemId: string): void;\n handleKeydown(menuId: string, event: KeyboardEvent): void;\n itemProps(menuId: string, itemId: string): Record<string, string | number | boolean | undefined>;\n menuProps(menuId: string): Record<string, string | boolean | undefined>;\n destroy(): void;\n};\n\ntype MenuStoreConfig = {\n onLockChange?: (locked: boolean) => void;\n};\n\nfunction enabledItems(instance: MenuInstance): MenuItemState[] {\n return instance.items.filter((item) => !item.disabled);\n}\n\nfunction itemIndex(instance: MenuInstance, itemId: string): number {\n return enabledItems(instance).findIndex((item) => item.id === itemId);\n}\n\nfunction moveActive(instance: MenuInstance, delta: number): string | null {\n const items = enabledItems(instance);\n if (items.length === 0) {\n return null;\n }\n\n const currentIndex = instance.activeItemId ? itemIndex(instance, instance.activeItemId) : -1;\n const nextIndex = (currentIndex + delta + items.length) % items.length;\n return items[nextIndex]?.id ?? null;\n}\n\nfunction firstItem(instance: MenuInstance): string | null {\n return enabledItems(instance)[0]?.id ?? null;\n}\n\nfunction lastItem(instance: MenuInstance): string | null {\n const items = enabledItems(instance);\n return items[items.length - 1]?.id ?? null;\n}\n\nfunction createInstance(options: MenuInstanceOptions = {}): MenuInstance {\n return {\n open: false,\n activeItemId: null,\n orientation: options.orientation ?? \"vertical\",\n closeOnSelect: options.closeOnSelect ?? true,\n items: [],\n container: null,\n trigger: null,\n onOpen: options.onOpen,\n onClose: options.onClose,\n onSelect: options.onSelect,\n };\n}\n\nfunction focusActiveItem(container: HTMLElement | null): void {\n if (!container) {\n return;\n }\n\n const active = container.querySelector<HTMLElement>('[role=\"menuitem\"][tabindex=\"0\"]');\n active?.focus();\n}\n\nfunction focusActiveMenu(instance: MenuInstance): void {\n focusActiveItem(instance.container);\n}\n\nfunction handleMenuKeydown(\n menuId: string,\n instance: MenuInstance,\n event: KeyboardEvent,\n selectItem: (menuId: string, itemId: string) => void,\n close: (menuId: string) => void\n): void {\n const vertical = instance.orientation === \"vertical\";\n const horizontal = instance.orientation === \"horizontal\";\n\n if (event.key === \"ArrowDown\" && vertical) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, 1);\n return;\n }\n\n if (event.key === \"ArrowUp\" && vertical) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, -1);\n return;\n }\n\n if (event.key === \"ArrowRight\" && horizontal) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, 1);\n return;\n }\n\n if (event.key === \"ArrowLeft\" && horizontal) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, -1);\n return;\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n instance.activeItemId = firstItem(instance);\n return;\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n instance.activeItemId = lastItem(instance);\n return;\n }\n\n if ((event.key === \"Enter\" || event.key === \" \") && instance.activeItemId) {\n event.preventDefault();\n selectItem(menuId, instance.activeItemId);\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(menuId);\n }\n}\n\n/** Creates the headless menu store. */\nexport function createMenuStore(config: MenuStoreConfig = {}): MenuStore {\n let lockCount = 0;\n\n function setLock(locked: boolean): void {\n if (locked) {\n if (lockCount === 0) {\n config.onLockChange?.(true);\n }\n lockCount++;\n return;\n }\n\n if (lockCount === 0) {\n return;\n }\n\n lockCount--;\n if (lockCount === 0) {\n config.onLockChange?.(false);\n }\n }\n\n function getOrCreate(store: MenuStore, id: string): MenuInstance {\n store.instances[id] ??= createInstance();\n return store.instances[id];\n }\n\n const store: MenuStore = {\n instances: {},\n\n register(id, options = {}) {\n this.instances[id] = createInstance(options);\n },\n\n unregister(id) {\n if (this.isOpen(id)) {\n this.close(id);\n }\n delete this.instances[id];\n },\n\n registerItem(menuId, itemId, options = {}) {\n const instance = getOrCreate(this, menuId);\n const existing = instance.items.find((item) => item.id === itemId);\n if (existing) {\n existing.disabled = options.disabled ?? existing.disabled;\n existing.parentId = options.parentId ?? existing.parentId;\n return;\n }\n\n instance.items.push({\n id: itemId,\n disabled: options.disabled ?? false,\n parentId: options.parentId ?? null,\n });\n },\n\n unregisterItem(menuId, itemId) {\n const instance = this.instances[menuId];\n if (!instance) {\n return;\n }\n\n instance.items = instance.items.filter((item) => item.id !== itemId);\n if (instance.activeItemId === itemId) {\n instance.activeItemId = firstItem(instance);\n }\n },\n\n open(id) {\n const instance = getOrCreate(this, id);\n if (instance.open) {\n return;\n }\n\n instance.open = true;\n if (!instance.activeItemId) {\n instance.activeItemId = firstItem(instance);\n }\n\n setLock(true);\n\n instance.onOpen?.();\n queueMicrotask(() => focusActiveMenu(instance));\n },\n\n close(id) {\n const instance = this.instances[id];\n if (!instance?.open) {\n return;\n }\n\n instance.open = false;\n\n setLock(false);\n\n instance.onClose?.();\n },\n\n toggle(id) {\n if (this.isOpen(id)) {\n this.close(id);\n } else {\n this.open(id);\n }\n },\n\n isOpen(id) {\n return this.instances[id]?.open ?? false;\n },\n\n activeItem(id) {\n return this.instances[id]?.activeItemId ?? null;\n },\n\n setActiveItem(menuId, itemId) {\n const instance = getOrCreate(this, menuId);\n if (itemId === null) {\n instance.activeItemId = null;\n return;\n }\n\n const item = instance.items.find((entry) => entry.id === itemId);\n if (item && !item.disabled) {\n instance.activeItemId = itemId;\n }\n },\n\n bindMenu(menuId, container) {\n const instance = getOrCreate(this, menuId);\n instance.container = container;\n\n if (instance.open) {\n queueMicrotask(() => focusActiveMenu(instance));\n }\n },\n\n bindTrigger(menuId, trigger) {\n const instance = getOrCreate(this, menuId);\n instance.trigger = trigger;\n },\n\n handleOutsideClick(menuId, event) {\n const instance = this.instances[menuId];\n if (!instance?.open) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof Node)) {\n return;\n }\n\n if (instance.trigger?.contains(target) || instance.container?.contains(target)) {\n return;\n }\n\n this.close(menuId);\n },\n\n selectItem(menuId, itemId) {\n const instance = this.instances[menuId];\n const item = instance?.items.find((entry) => entry.id === itemId);\n if (!(instance && item) || item.disabled) {\n return;\n }\n\n instance.activeItemId = itemId;\n instance.onSelect?.(itemId);\n\n if (instance.closeOnSelect) {\n this.close(menuId);\n }\n },\n\n handleKeydown(menuId, event) {\n const instance = this.instances[menuId];\n if (instance?.open) {\n handleMenuKeydown(\n menuId,\n instance,\n event,\n this.selectItem.bind(this),\n this.close.bind(this)\n );\n queueMicrotask(() => focusActiveMenu(instance));\n }\n },\n\n itemProps(menuId, itemId) {\n const instance = this.instances[menuId];\n const item = instance?.items.find((entry) => entry.id === itemId);\n const active = instance?.activeItemId === itemId;\n\n return {\n role: \"menuitem\",\n tabindex: active ? 0 : -1,\n \"aria-disabled\": item?.disabled ?? false,\n };\n },\n\n menuProps(menuId) {\n const instance = this.instances[menuId];\n return {\n role: \"menu\",\n \"aria-orientation\": instance?.orientation,\n };\n },\n\n destroy() {\n for (const id of Object.keys(this.instances)) {\n this.unregister(id);\n }\n lockCount = 0;\n config.onLockChange?.(false);\n },\n };\n\n return store;\n}\n","import type AlpineType from \"alpinejs\";\nimport { createMenuStore, type MenuStore } from \"./store.js\";\n\nexport {\n createMenuStore,\n type MenuInstanceOptions,\n type MenuItemOptions,\n type MenuOrientation,\n type MenuStore,\n} from \"./store.js\";\n\nexport interface MenuPluginOptions {\n onLockChange?: (locked: boolean) => void;\n}\n\n/** Builds typed menu plugin options. */\nexport function menuOptions<const T extends MenuPluginOptions>(options: T): T {\n return options;\n}\n\n/** Alpine.js menu plugin. Registers `$store.menu`. */\nexport default function menuPlugin(options: MenuPluginOptions = {}): AlpineType.PluginCallback {\n return function registerMenu(Alpine) {\n const store = createMenuStore({\n onLockChange: options.onLockChange,\n });\n Alpine.store(\"menu\", store);\n Alpine.magic(\"menu\", () => Alpine.store(\"menu\"));\n };\n}\n\ndeclare global {\n namespace Alpine {\n interface Stores {\n menu: MenuStore;\n }\n interface Magics<T> {\n $menu: MenuStore;\n }\n }\n}\n"],"mappings":"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","names":["store"]}
1
+ {"version":3,"sources":["../src/store.ts","../src/index.ts"],"sourcesContent":["export type MenuOrientation = \"vertical\" | \"horizontal\";\n\nexport type MenuItemState = {\n id: string;\n disabled: boolean;\n parentId: string | null;\n};\n\nexport type MenuInstance = {\n open: boolean;\n activeItemId: string | null;\n orientation: MenuOrientation;\n closeOnSelect: boolean;\n group: string | null;\n items: MenuItemState[];\n container: HTMLElement | null;\n trigger: HTMLElement | null;\n onOpen?: () => void;\n onClose?: () => void;\n onSelect?: (itemId: string) => void;\n};\n\nexport type MenuItemOptions = {\n disabled?: boolean;\n parentId?: string | null;\n};\n\nexport type MenuInstanceOptions = {\n orientation?: MenuOrientation;\n closeOnSelect?: boolean;\n /** When store `exclusive` is `false`, only one menu per group may be open at a time. */\n group?: string;\n onOpen?: () => void;\n onClose?: () => void;\n onSelect?: (itemId: string) => void;\n};\n\nexport type MenuStore = {\n /** Reactive registry of menu instances. */\n instances: Record<string, MenuInstance>;\n open(id: string): void;\n close(id: string): void;\n toggle(id: string): void;\n isOpen(id: string): boolean;\n activeItem(id: string): string | null;\n register(id: string, options?: MenuInstanceOptions): void;\n unregister(id: string): void;\n registerItem(menuId: string, itemId: string, options?: MenuItemOptions): void;\n unregisterItem(menuId: string, itemId: string): void;\n bindMenu(menuId: string, container: HTMLElement | null): void;\n bindTrigger(menuId: string, trigger: HTMLElement | null): void;\n handleOutsideClick(menuId: string, event: MouseEvent): void;\n setActiveItem(menuId: string, itemId: string | null): void;\n selectItem(menuId: string, itemId: string): void;\n handleKeydown(menuId: string, event: KeyboardEvent): void;\n /** Close open menus on outside click — pass `menuIds` when wiring multiple menus on one page. */\n handleWindowOutsideClick(event: MouseEvent, menuIds?: readonly string[]): void;\n /** Route keyboard events to the first open menu in `menuIds` (defaults to all registered). */\n handleWindowKeydown(event: KeyboardEvent, menuIds?: readonly string[]): void;\n itemProps(menuId: string, itemId: string): Record<string, string | number | boolean | undefined>;\n menuProps(menuId: string): Record<string, string | boolean | undefined>;\n destroy(): void;\n};\n\ntype MenuStoreConfig = {\n /** When true (default), opening a menu closes all other open menus. */\n exclusive?: boolean;\n onLockChange?: (locked: boolean) => void;\n};\n\nfunction enabledItems(instance: MenuInstance): MenuItemState[] {\n return instance.items.filter((item) => !item.disabled);\n}\n\nfunction itemIndex(instance: MenuInstance, itemId: string): number {\n return enabledItems(instance).findIndex((item) => item.id === itemId);\n}\n\nfunction moveActive(instance: MenuInstance, delta: number): string | null {\n const items = enabledItems(instance);\n if (items.length === 0) {\n return null;\n }\n\n const currentIndex = instance.activeItemId ? itemIndex(instance, instance.activeItemId) : -1;\n const nextIndex = (currentIndex + delta + items.length) % items.length;\n return items[nextIndex]?.id ?? null;\n}\n\nfunction firstItem(instance: MenuInstance): string | null {\n return enabledItems(instance)[0]?.id ?? null;\n}\n\nfunction lastItem(instance: MenuInstance): string | null {\n const items = enabledItems(instance);\n return items[items.length - 1]?.id ?? null;\n}\n\nfunction createInstance(options: MenuInstanceOptions = {}): MenuInstance {\n return {\n open: false,\n activeItemId: null,\n orientation: options.orientation ?? \"vertical\",\n closeOnSelect: options.closeOnSelect ?? true,\n group: options.group ?? null,\n items: [],\n container: null,\n trigger: null,\n onOpen: options.onOpen,\n onClose: options.onClose,\n onSelect: options.onSelect,\n };\n}\n\nfunction focusActiveItem(container: HTMLElement | null): void {\n if (!container) {\n return;\n }\n\n const active = container.querySelector<HTMLElement>('[role=\"menuitem\"][tabindex=\"0\"]');\n active?.focus();\n}\n\nfunction focusActiveMenu(instance: MenuInstance): void {\n focusActiveItem(instance.container);\n}\n\nfunction handleMenuKeydown(\n menuId: string,\n instance: MenuInstance,\n event: KeyboardEvent,\n selectItem: (menuId: string, itemId: string) => void,\n close: (menuId: string) => void\n): void {\n const vertical = instance.orientation === \"vertical\";\n const horizontal = instance.orientation === \"horizontal\";\n\n if (event.key === \"ArrowDown\" && vertical) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, 1);\n return;\n }\n\n if (event.key === \"ArrowUp\" && vertical) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, -1);\n return;\n }\n\n if (event.key === \"ArrowRight\" && horizontal) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, 1);\n return;\n }\n\n if (event.key === \"ArrowLeft\" && horizontal) {\n event.preventDefault();\n instance.activeItemId = moveActive(instance, -1);\n return;\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n instance.activeItemId = firstItem(instance);\n return;\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n instance.activeItemId = lastItem(instance);\n return;\n }\n\n if ((event.key === \"Enter\" || event.key === \" \") && instance.activeItemId) {\n event.preventDefault();\n selectItem(menuId, instance.activeItemId);\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(menuId);\n }\n}\n\n/** Creates the headless menu store. */\nexport function createMenuStore(config: MenuStoreConfig = {}): MenuStore {\n const exclusive = config.exclusive ?? true;\n let lockCount = 0;\n\n function setLock(locked: boolean): void {\n if (locked) {\n if (lockCount === 0) {\n config.onLockChange?.(true);\n }\n lockCount++;\n return;\n }\n\n if (lockCount === 0) {\n return;\n }\n\n lockCount--;\n if (lockCount === 0) {\n config.onLockChange?.(false);\n }\n }\n\n function getOrCreate(store: MenuStore, id: string): MenuInstance {\n store.instances[id] ??= createInstance();\n return store.instances[id];\n }\n\n function closeMenu(menuStore: MenuStore, id: string, suppressLock = false): void {\n const instance = menuStore.instances[id];\n if (!instance?.open) {\n return;\n }\n\n instance.open = false;\n\n if (!suppressLock) {\n setLock(false);\n }\n\n instance.onClose?.();\n }\n\n function closeOtherMenus(menuStore: MenuStore, openingId: string): number {\n const opening = menuStore.instances[openingId];\n const openingGroup = opening?.group ?? null;\n let closedCount = 0;\n\n for (const menuId of Object.keys(menuStore.instances)) {\n if (menuId === openingId || !menuStore.isOpen(menuId)) {\n continue;\n }\n\n const other = menuStore.instances[menuId];\n const shouldClose =\n exclusive !== false || (openingGroup !== null && other.group === openingGroup);\n\n if (shouldClose) {\n closeMenu(menuStore, menuId, true);\n closedCount++;\n }\n }\n\n return closedCount;\n }\n\n const store: MenuStore = {\n instances: {},\n\n register(id, options = {}) {\n this.instances[id] = createInstance(options);\n },\n\n unregister(id) {\n if (this.isOpen(id)) {\n this.close(id);\n }\n delete this.instances[id];\n },\n\n registerItem(menuId, itemId, options = {}) {\n const instance = getOrCreate(this, menuId);\n const existing = instance.items.find((item) => item.id === itemId);\n if (existing) {\n existing.disabled = options.disabled ?? existing.disabled;\n existing.parentId = options.parentId ?? existing.parentId;\n return;\n }\n\n instance.items.push({\n id: itemId,\n disabled: options.disabled ?? false,\n parentId: options.parentId ?? null,\n });\n },\n\n unregisterItem(menuId, itemId) {\n const instance = this.instances[menuId];\n if (!instance) {\n return;\n }\n\n instance.items = instance.items.filter((item) => item.id !== itemId);\n if (instance.activeItemId === itemId) {\n instance.activeItemId = firstItem(instance);\n }\n },\n\n open(id) {\n const instance = getOrCreate(this, id);\n if (instance.open) {\n return;\n }\n\n const closedCount = closeOtherMenus(this, id);\n\n instance.open = true;\n if (!instance.activeItemId) {\n instance.activeItemId = firstItem(instance);\n }\n\n if (closedCount === 0) {\n setLock(true);\n }\n\n instance.onOpen?.();\n queueMicrotask(() => focusActiveMenu(instance));\n },\n\n close(id) {\n closeMenu(this, id);\n },\n\n toggle(id) {\n if (this.isOpen(id)) {\n this.close(id);\n } else {\n this.open(id);\n }\n },\n\n isOpen(id) {\n return this.instances[id]?.open ?? false;\n },\n\n activeItem(id) {\n return this.instances[id]?.activeItemId ?? null;\n },\n\n setActiveItem(menuId, itemId) {\n const instance = getOrCreate(this, menuId);\n if (itemId === null) {\n instance.activeItemId = null;\n return;\n }\n\n const item = instance.items.find((entry) => entry.id === itemId);\n if (item && !item.disabled) {\n instance.activeItemId = itemId;\n }\n },\n\n bindMenu(menuId, container) {\n const instance = getOrCreate(this, menuId);\n instance.container = container;\n\n if (instance.open) {\n queueMicrotask(() => focusActiveMenu(instance));\n }\n },\n\n bindTrigger(menuId, trigger) {\n const instance = getOrCreate(this, menuId);\n instance.trigger = trigger;\n },\n\n handleOutsideClick(menuId, event) {\n const instance = this.instances[menuId];\n if (!instance?.open) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof Node)) {\n return;\n }\n\n if (instance.trigger?.contains(target) || instance.container?.contains(target)) {\n return;\n }\n\n this.close(menuId);\n },\n\n selectItem(menuId, itemId) {\n const instance = this.instances[menuId];\n const item = instance?.items.find((entry) => entry.id === itemId);\n if (!(instance && item) || item.disabled) {\n return;\n }\n\n instance.activeItemId = itemId;\n instance.onSelect?.(itemId);\n\n if (instance.closeOnSelect) {\n this.close(menuId);\n }\n },\n\n handleKeydown(menuId, event) {\n const instance = this.instances[menuId];\n if (instance?.open) {\n handleMenuKeydown(\n menuId,\n instance,\n event,\n this.selectItem.bind(this),\n this.close.bind(this)\n );\n queueMicrotask(() => focusActiveMenu(instance));\n }\n },\n\n handleWindowOutsideClick(event, menuIds) {\n const ids = menuIds ?? Object.keys(this.instances);\n for (const menuId of ids) {\n this.handleOutsideClick(menuId, event);\n }\n },\n\n handleWindowKeydown(event, menuIds) {\n const ids = menuIds ?? Object.keys(this.instances);\n for (const menuId of ids) {\n if (this.isOpen(menuId)) {\n this.handleKeydown(menuId, event);\n return;\n }\n }\n },\n\n itemProps(menuId, itemId) {\n const instance = this.instances[menuId];\n const item = instance?.items.find((entry) => entry.id === itemId);\n const active = instance?.activeItemId === itemId;\n\n return {\n role: \"menuitem\",\n tabindex: active ? 0 : -1,\n \"aria-disabled\": item?.disabled ?? false,\n };\n },\n\n menuProps(menuId) {\n const instance = this.instances[menuId];\n return {\n role: \"menu\",\n \"aria-orientation\": instance?.orientation,\n };\n },\n\n destroy() {\n for (const id of Object.keys(this.instances)) {\n this.unregister(id);\n }\n lockCount = 0;\n config.onLockChange?.(false);\n },\n };\n\n return store;\n}\n","import type AlpineType from \"alpinejs\";\nimport { createMenuStore, type MenuStore } from \"./store.js\";\n\nexport {\n createMenuStore,\n type MenuInstanceOptions,\n type MenuItemOptions,\n type MenuOrientation,\n type MenuStore,\n} from \"./store.js\";\n\nexport interface MenuPluginOptions {\n /** When true (default), opening a menu closes all other open menus. */\n exclusive?: boolean;\n onLockChange?: (locked: boolean) => void;\n}\n\n/** Builds typed menu plugin options. */\nexport function menuOptions<const T extends MenuPluginOptions>(options: T): T {\n return options;\n}\n\n/** Alpine.js menu plugin. Registers `$store.menu`. */\nexport default function menuPlugin(options: MenuPluginOptions = {}): AlpineType.PluginCallback {\n return function registerMenu(Alpine) {\n const store = createMenuStore({\n exclusive: options.exclusive,\n onLockChange: options.onLockChange,\n });\n Alpine.store(\"menu\", store);\n Alpine.magic(\"menu\", () => Alpine.store(\"menu\"));\n };\n}\n\ndeclare global {\n namespace Alpine {\n interface Stores {\n menu: MenuStore;\n }\n interface Magics<T> {\n $menu: MenuStore;\n }\n }\n}\n"],"mappings":"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","names":["store"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ailuracode/alpine-menu",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Alpine.js headless accessible menu store",
5
5
  "type": "module",
6
6
  "license": "MIT",