@enegalan/contextmenu.js 1.4.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eneko Galan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,312 @@
1
+ # contextmenu.js
2
+
3
+ <img src="logo.png" width="512" height="512" alt="contextmenu.js" />
4
+
5
+ A smooth, customizable context-menu library. TypeScript-first, framework-agnostic, with keyboard and screen-reader support.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @enegalan/contextmenu.js
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```js
16
+ import { createContextMenu } from "@enegalan/contextmenu.js";
17
+ import "@enegalan/contextmenu.js/dist/style.css";
18
+
19
+ const menu = createContextMenu({
20
+ menu: [
21
+ { label: "Copy", shortcut: "Ctrl+C", onClick: () => copy() },
22
+ { label: "Paste", shortcut: "Ctrl+V", onClick: ({ close }) => { paste(); close(); } },
23
+ { type: "separator" },
24
+ { type: "submenu", label: "More", children: [
25
+ { label: "Rename", onClick: () => rename() },
26
+ { label: "Delete", onClick: () => remove() },
27
+ ]},
28
+ ],
29
+ });
30
+
31
+ // Open on right-click (desktop) or long-press (touch)
32
+ menu.bind(element);
33
+
34
+ // Or manually
35
+ element.addEventListener("contextmenu", (e) => { e.preventDefault(); menu.open(e); });
36
+
37
+ // Programmatic
38
+ const selected = await menu.open(x, y);
39
+ menu.close();
40
+ menu.openAtElement(button, { placement: "bottom-start" });
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Instance methods
46
+
47
+ What you get from `createContextMenu(config)`:
48
+
49
+ | Method | Description |
50
+ |--------|-------------|
51
+ | `open(x?, y?)` / `open(event)` | Show menu at coordinates or at the event position. Returns a `Promise<MenuItem \| undefined>` that resolves with the selected item when the menu closes, or `undefined` if closed without selection. |
52
+ | `close()` | Close the menu. Returns a `Promise<void>` that resolves when the close animation finishes. |
53
+ | `toggle(x?, y?)` | Open if closed, close if open. |
54
+ | `openAtElement(el, options?)` | Show menu next to an element. `options.placement`: `"bottom-start"`, `"top-end"`, `"auto"`, etc. `options.offset`: `{ x, y }` in px. |
55
+ | `isOpen()` | `true` if the menu is visible. |
56
+ | `getAnchor()` | Returns `{ x, y }` of the last open anchor, or `null`. |
57
+ | `getMenu()` | Copy of the current menu (array of items). |
58
+ | `getRootElement()` | The wrapper DOM element (for tests or styling). |
59
+ | `unbind(element?)` | Remove bind from the given element, or from the currently bound element if no argument. |
60
+ | `setMenu(menu)` | Replace the menu. `menu` is an array of menu items. |
61
+ | `updateMenu(updater)` | Change the menu from current state. `updater` is a function: `(currentItems) => newItems`. See example below. |
62
+ | `setTheme(theme)` | Change theme at runtime. `theme`: `{ class?: string, tokens?: { bg: "...", fg: "..." } }` or `undefined` to clear. |
63
+ | `setPosition(position)` | Change position config for next open. `position`: `{ offset?: { x, y }, padding?: number, flip?: boolean, shift?: boolean }`. |
64
+ | `setAnimation(animation)` | Change animation at runtime. `animation`: `{ type?: "fade" | "slide", enter?, leave?, disabled? }` (times in ms). |
65
+ | `bind(element, options?)` | Open menu on right-click / long-press. `options.longPressMs`: delay for long-press (default 500). |
66
+ | `destroy()` | Remove menu and all listeners. |
67
+
68
+ **updateMenu example** — e.g. to persist a checkbox:
69
+
70
+ ```js
71
+ menu.updateMenu((current) =>
72
+ current.map((item) =>
73
+ item.type === "checkbox" && item.label === "Dark mode"
74
+ ? { ...item, checked: !item.checked }
75
+ : item
76
+ )
77
+ );
78
+ ```
79
+
80
+ **setTheme / setPosition / setAnimation example** — same shape as in config:
81
+
82
+ ```js
83
+ menu.setTheme({ class: "my-dark", tokens: { bg: "#1a1a1a", fg: "#eee" } });
84
+ menu.setPosition({ padding: 12, zIndexBase: 10000, submenuZIndexStep: 1 });
85
+ menu.setAnimation({ enter: 150, leave: 100 });
86
+ menu.setTheme(undefined); // clear theme
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Config options
92
+
93
+ What you pass to `createContextMenu({ ... })`:
94
+
95
+ | Option | Type | Description |
96
+ |--------|------|-------------|
97
+ | `menu` | `MenuItem[]` or `() => MenuItem[]` | The menu tree. If a function, it runs each time the menu opens (dynamic menu). |
98
+ | `submenuArrow` | `boolean` or object | `true` = default chevron SVG. Object: `{ icon?, size?, className?, opacity? }`; omit `icon` to use the CSS triangle. |
99
+ | `spinner` | `{ icon?, size?, speed? }` | Default loading spinner. `icon`: SVG string or HTMLElement. `size`: px or CSS length. `speed`: ms per full rotation (default 600). Overridable per item via `loadingIcon`, `loadingSize`, `loadingSpeed`. |
100
+ | `theme` | `{ class?, tokens? }` | `class`: CSS class on menu. `tokens`: e.g. `{ bg: "#111", fg: "#eee" }` (sets `--cm-bg`, `--cm-fg`). |
101
+ | `animation` | `{ type?, enter?, leave?, disabled? }` | `type`: `"fade"` (opacity + scale) or `"slide"` (opacity + translate). `enter` / `leave`: ms or `{ duration, easing }`. `disabled: true` = no animation. |
102
+ | `position` | `{ offset?, padding?, flip?, shift?, zIndexBase?, submenuZIndexStep? }` | `offset`: `{ x, y }`. `padding`: viewport padding (px). `flip` / `shift`: keep menu in view. `zIndexBase`: base z-index for root menu. `submenuZIndexStep`: increment per submenu level so each stacks above the previous (0 = no increment). |
103
+ | `portal` | `HTMLElement` or function | Where to mount the menu. Default: `document.body`. |
104
+ | `getAnchor` | `() => { x, y }` or `DOMRect` | Used when `open()` is called with no arguments. |
105
+ | `submenuPlacement` | `"right"` \| `"left"` \| `"auto"` | Where to open submenus. `"auto"` uses RTL and viewport space (default). |
106
+ | `bind` | `HTMLElement` or `{ element, options? }` | Same as calling `menu.bind(element, options)` after create. |
107
+ | `onOpen` | `(event?: MouseEvent) => void` | Called when menu opens. `event` is set when opened by right-click or bind. |
108
+ | `onClose` | `(context?: CloseContext) => void` | Called when menu closes (after leave animation). `context`: `{ selectedItem?, anchor }`. |
109
+ | `onBeforeOpen` | `(event?, context?: OpenContext) => boolean \| void \| Promise<...>` | Called before opening. `context`: `{ x, y, target?, event? }`. Return `false` (or a Promise resolving to `false`) to cancel. |
110
+ | `onAfterClose` | `(context?: CloseContext) => void` | Called after the menu is fully closed (same context as `onClose`). |
111
+ | `onBeforeClose` | `() => boolean \| void \| Promise<...>` | Called before closing. Return `false` (or a Promise resolving to `false`) to cancel. |
112
+ | `onItemHover` | `(payload: { item, nativeEvent }) => void` | Called when the user hovers or focuses an interactive item. |
113
+ | `closeOnResize` | `boolean` | If `true`, menu closes on window resize. |
114
+ | `shortcutIcons` | `Record<string, string \| HTMLElement>` | Optional map of shortcut part names to SVG string or HTMLElement. Keys are the same names used in shortcuts (e.g. `ctrl`, `shift`, `enter`, `tab`, `cmd`, `alt`). When provided, those parts are rendered as icons instead of Unicode symbols (useful on Windows). Each icon is wrapped in a span with class `.cm-shortcut-icon` for styling. |
115
+ | `platform` | `"mac"` \| `"win"` \| `"auto"` | Override platform so the menu adapts to that OS (e.g. shortcut display). Default `"auto"` detects. Set to `"win"` on macOS to preview Windows look. |
116
+
117
+ ---
118
+
119
+ ## Menu item types
120
+
121
+ Each entry in `menu` (or in a submenu’s `children`) is one of these.
122
+
123
+ **Action** — clickable row
124
+
125
+ - `label` (string), `icon?`, `shortcut?`, `badge?` (string, number, or `BadgeConfig`: `{ content?, className?, render? }` for full control), `disabled?`, `loading?`, `variant?`, `onClick?`, `closeOnAction?`, `render?`
126
+ - `onClick` receives `{ item, nativeEvent, close }`. By default the menu closes on click; set `closeOnAction: false` to keep it open.
127
+ - `loading`: when `true`, shows a spinner and blocks interaction (use `setMenu` / `updateMenu` to clear). Optional: `loadingIcon` (SVG or HTMLElement), `loadingSize` (px or CSS length), `loadingSpeed` (ms per rotation) to override config.
128
+ - `variant`: `"default"` | `"danger"` | `"info"` | `"success"` | `"warning"` | `"muted"` (adds class e.g. `cm-item--danger`).
129
+
130
+ **Link** — navigation item
131
+
132
+ - `type: "link"`, `label`, `href`, optional `icon?`, `shortcut?`, `badge?` (string, number, or `BadgeConfig`), `target?` (e.g. `"_blank"`), `rel?` (e.g. `"noopener"`), `disabled?`, `loading?`, `variant?`, `className?`
133
+ - Renders as `<a>`. Ctrl/Cmd+click opens in new tab without preventing default.
134
+
135
+ **Submenu** — opens a nested menu
136
+
137
+ - `type: "submenu"`, `label`, `children` (array of items, or `() => MenuItem[]`, or `() => Promise<MenuItem[]>` for lazy loading), `icon?`, `shortcut?`, `badge?` (string, number, or `BadgeConfig`), `disabled?`, `variant?`, `submenuPlacement?`
138
+ - `children` as a function is resolved when the submenu opens (useful for async data).
139
+ - `submenuPlacement`: `"right"` | `"left"` | `"auto"` overrides the config for this submenu.
140
+ - Opens on hover or Arrow Right / Enter.
141
+
142
+ **Separator**
143
+
144
+ - `type: "separator"` (optional `id`, `className`).
145
+
146
+ **Checkbox**
147
+
148
+ - `type: "checkbox"`, `label`, `checked?`, `onChange?`, plus `leadingIcon?`, `shortcut?`, `icon?` / `uncheckedIcon?`, `disabled?`, `loading?`, `closeOnAction?`, `variant?`, `render?`
149
+ - `onChange` receives `{ item, checked, nativeEvent, close }`. State is not stored; use a function menu or `setMenu` / `updateMenu` to persist.
150
+
151
+ **Radio**
152
+
153
+ - `type: "radio"`, `label`, `name`, `value`, `checked?`, `onSelect?`, plus same optional props as checkbox (including `loading?`).
154
+ - One item per group (same `name`) should have `checked: true`. Update menu to reflect selection.
155
+
156
+ **Label** — non-clickable header
157
+
158
+ - `type: "label"`, `label` (string), optional `id`, `className`.
159
+
160
+ **Custom events**
161
+
162
+ Every menu item has an optional `events` property: `EventRegistry | (() => EventRegistry)`. `EventRegistry` is a map of DOM event names to either a listener function or an object `{ listener, options? }` (where `options` is `EventListenerOptions`, e.g. `{ passive: true }`). Handlers are attached to the item’s DOM element.
163
+
164
+ ```js
165
+ {
166
+ label: "Hover here!",
167
+ events: {
168
+ mouseenter: (e) => { e.target.style.animation = "blinker 1s linear infinite"; },
169
+ mouseleave: {
170
+ listener: (e) => { e.target.style.animation = ""; },
171
+ options: { passive: true }
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Shortcut display (symbols)
180
+
181
+ The `shortcut` string is shown next to the item. Use the names below so the library can render **modifier** and **key** symbols (e.g. ⌘↵ instead of "Cmd+Enter"). Names are **case-insensitive**.
182
+
183
+ **Format:** `Modifier+Modifier+Key` — use `+` to separate parts. The last segment is the key; the rest are modifiers.
184
+
185
+ **Modifiers** (display depends on platform):
186
+
187
+ | You write | macOS / iOS display | Windows / Linux display |
188
+ |-----------|---------------------|--------------------------|
189
+ | `Ctrl` | ⌘ (shown as Cmd) | ⌃ |
190
+ | `Cmd` | ⌘ | Win icon |
191
+ | `Alt` | ⌥ | ⎇ |
192
+ | `Shift` | ⇧ | ⇧ |
193
+ | `Win` / `Windows` | ⌘ (as Cmd) | Win icon |
194
+
195
+ **Keys** (use these exact names to get symbols):
196
+
197
+ | You write | Display |
198
+ |---------------|---------|
199
+ | `Enter` / `Return` | ↵ |
200
+ | `Tab` | ⇥ |
201
+ | `Backspace` | ⌫ |
202
+ | `Escape` / `Esc` | ⎋ |
203
+ | `Delete` | ⌦ |
204
+ | `Space` | ␣ |
205
+ | `Left` / `Right` / `Up` / `Down` (or `ArrowLeft`, etc.) | ← → ↑ ↓ |
206
+ | `Home` / `End` | ⇱ ⇲ |
207
+ | `PageUp` / `PageDown` | ⇞ ⇟ |
208
+ | `Insert` / `Ins` | ⎀ |
209
+
210
+ Single letters and other keys (e.g. `C`, `F1`) are shown as-is (letters in uppercase). Examples:
211
+
212
+ - `"Ctrl+C"` → ⌘C (Mac) or ⌃C (Win)
213
+ - `"Ctrl+Shift+Enter"` → ⌘⇧↵ (Mac) or ⌃⇧↵ (Win)
214
+ - `"Alt+Tab"` → ⌥⇥ (Mac) or ⎇⇥ (Win)
215
+
216
+ **Using SVG/icons instead of symbols**
217
+
218
+ To use icons for other shortcut parts (e.g. when symbols don’t render well), pass `shortcutIcons` in the config. On Windows the Win key uses a built-in SVG icon by default. Keys must match the shortcut part names (lowercase): `ctrl`, `shift`, `alt`, `cmd`, `win`, `enter`, `tab`, `escape`, etc.
219
+
220
+ ```js
221
+ createContextMenu({
222
+ menu: [...],
223
+ shortcutIcons: {
224
+ ctrl: '<svg viewBox="0 0 24 24">...</svg>',
225
+ shift: '<svg viewBox="0 0 24 24">...</svg>',
226
+ enter: '<svg viewBox="0 0 24 24">...</svg>',
227
+ tab: '<svg viewBox="0 0 24 24">...</svg>',
228
+ },
229
+ });
230
+ ```
231
+
232
+ Each icon is wrapped in a span with class `.cm-shortcut-icon` so you can size or style them in CSS.
233
+
234
+ ---
235
+
236
+ ## Theming
237
+
238
+ Load the default CSS and override with variables:
239
+
240
+ ```css
241
+ @import "@enegalan/contextmenu.js/dist/style.css";
242
+
243
+ .cm-menu {
244
+ --cm-bg: #1e1e1e;
245
+ --cm-fg: #eee;
246
+ --cm-radius: 8px;
247
+ }
248
+ ```
249
+
250
+ Or pass `theme` when creating the menu:
251
+
252
+ ```js
253
+ createContextMenu({
254
+ menu: [...],
255
+ theme: { class: "my-menu", tokens: { bg: "#1e1e1e", fg: "#eee" } },
256
+ });
257
+ ```
258
+
259
+ **Main variables:** `--cm-bg`, `--cm-fg`, `--cm-radius`, `--cm-shadow`, `--cm-menu-padding`, `--cm-menu-min-width`, `--cm-menu-max-height` (use `none` for no scroll), `--cm-item-radius`, `--cm-item-padding-x`, `--cm-item-padding-y`, `--cm-item-hover-bg`, `--cm-item-active-bg`, `--cm-font-size`, `--cm-border`, `--cm-separator-bg`, `--cm-separator-margin`, `--cm-separator-height`, `--cm-disabled-opacity`, `--cm-z-index`, `--cm-spinner-size`. **Shortcut:** `--cm-shortcut-font-size`, `--cm-shortcut-opacity`, `--cm-shortcut-icon-size` (size of each shortcut icon, default `1em`). **Badge:** `--cm-badge-font-size`, `--cm-badge-opacity`, `--cm-badge-padding`, `--cm-badge-border-radius`, `--cm-badge-box-shadow`, `--cm-badge-background`, `--cm-badge-border-width`, `--cm-badge-border-style`, `--cm-badge-border-color`. Variants: `.cm-item--danger`, `.cm-item--info`, `.cm-item--success`, `.cm-item--warning`, `.cm-item--muted`.
260
+
261
+ **Animation variables** (also set by config `animation` at runtime): `--cm-enter-duration` (default 120ms), `--cm-leave-duration` (default 80ms), `--cm-enter-easing` (default ease-out), `--cm-leave-easing` (default ease-in). Override in CSS or via the `animation` option. Use `animation.type: "slide"` for a slide-in effect instead of fade+scale.
262
+
263
+ **Badge:** Items with `badge` (action, link, submenu) render a pill to the right. Use a string/number, or `BadgeConfig`: `{ content?, className? }` for text + extra classes, or `{ render: () => HTMLElement }` for a custom element. Style the default pill with `.cm-item-badge`.
264
+
265
+ ---
266
+
267
+ ## Singleton behavior
268
+
269
+ Only one context menu is open at a time. When a new menu is opened (from any instance created with this library), any other open menu is closed first.
270
+
271
+ ---
272
+
273
+ ## Accessibility
274
+
275
+ - **ARIA:** Root `role="menu"`, items `menuitem` / `menuitemcheckbox` / `menuitemradio`, submenus `aria-haspopup` and `aria-expanded`, separators `separator`, labels `presentation`.
276
+ - **Keyboard:** Arrows (move, open/close submenu), Enter/Space (activate), Escape (close), Home/End (first/last). **Shortcuts:** With the menu open, pressing an item’s shortcut (e.g. `Ctrl+C` or `Cmd+C`) runs that item; Ctrl and Cmd are treated as equivalent (macOS and Windows/Linux). Focus returns to trigger on close.
277
+ - **Focus:** Roving tabindex on the menu.
278
+
279
+ ---
280
+
281
+ ## Bundle size
282
+
283
+ Build output is minified. Approximate sizes:
284
+
285
+ | Asset | Size |
286
+ |-------|------|
287
+ | `dist/index.js` (ESM) | ~27 KB |
288
+ | `dist/index.cjs` (CJS) | ~28 KB |
289
+ | `dist/style.css` | ~8 KB (minified) |
290
+
291
+ ---
292
+
293
+ ## Build
294
+
295
+ ```bash
296
+ npm install
297
+ npm run build
298
+ ```
299
+
300
+ Output: `dist/index.js` (ESM), `dist/index.cjs` (CJS), `dist/index.d.ts`, `dist/style.css` (minified).
301
+
302
+ **Dev + example:**
303
+
304
+ ```bash
305
+ npm run dev
306
+ ```
307
+
308
+ ---
309
+
310
+ ## License
311
+
312
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var e,n=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,i={};((e,t)=>{for(var o in t)n(e,o,{get:t[o],enumerable:!0})})(i,{createContextMenu:()=>_e}),module.exports=(e=i,((e,i,s,l)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let s of o(i))r.call(e,s)||void 0===s||n(e,s,{get:()=>i[s],enumerable:!(l=t(i,s))||l.enumerable});return e})(n({},"__esModule",{value:!0}),e));var s="cm-",l="_cmItem",a="_cmSubmenu",u="cm-menu",c="cm-open",d="cm-leave",m="cm-submenu-open",p=200,f=150,h=500,b=600,g="cm-icon",v="cm-submenu-arrow",C="cm-submenu-arrow--icon",y="cm-separator",S="cm-item",w="cm-item-loading",E="cm-item-leading",T="cm-item-label",H="cm-spinner",k="cm-spinner--custom",x="--cm-spinner-duration",A="cm-label",L="cm-item-checkbox",P="cm-checked",O="cm-check",I="cm-check--custom",N="cm-shortcut",z="cm-shortcut-icon",R="cm-item-badge",M="cm-item-radio",D="cm-radio",F="cm-radio--custom",$="cm-submenu-trigger",_="cm-wrapper",B="cm-submenu",W="[role='menu']",j="data-cm-theme-class",K="data-cm-animation",q="--cm-",X="--cm-enter-duration",Y="--cm-leave-duration",U="--cm-enter-easing",Z="--cm-leave-easing",G='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4875 4875" fill="currentColor" aria-hidden="true"><path xmlns="http://www.w3.org/2000/svg" fill="currentColor" d="M0 0h2311v2310H0zm2564 0h2311v2310H2564zM0 2564h2311v2311H0zm2564 0h2311v2311H2564"/></svg>',J='<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6-6-6z"/></svg>',Q={cmd:"⌘",alt:"⌥",win:"⌘",windows:"⌘"},V={cmd:"⊞",alt:"⎇",win:{text:"⊞",icon:G},windows:{text:"⊞",icon:G}},ee={ctrl:"⌃",shift:"⇧",enter:"↵",return:"↵",tab:"⇥",backspace:"⌫",escape:"⎋",esc:"⎋",delete:"⌦",space:"␣",left:"←",right:"→",up:"↑",down:"↓",arrowleft:"←",arrowright:"→",arrowup:"↑",arrowdown:"↓",home:"⇱",end:"⇲",pageup:"⇞",pagedown:"⇟",insert:"⎀",ins:"⎀"},ne=new Set;function te(){const e=document.documentElement;return{vw:e.clientWidth,vh:e.clientHeight}}function oe(e,n){for(const[t,o]of Object.entries(n))e.setAttribute(t,o)}function re(e,n){for(const[t,o]of Object.entries(n))t.startsWith("--")?e.style.setProperty(t,o):e.style[t]=o}function ie(e,...n){for(const t of n)t&&e.classList.add(...t.trim().split(/\s+/).filter(Boolean))}function se(){if("undefined"==typeof navigator)return!1;const e=navigator.userAgentData?.platform;if("macOS"===e||"iOS"===e)return!0;const n=navigator.userAgent??"";return/Mac|iPhone|iPod|iPad/i.test(n)}function le(e){const n={...e};if("visible"in n&&void 0===n.visible&&(n.visible=!0),"type"in e&&null!=e.type&&""!==e.type||("children"in n?n.type="submenu":"href"in n&&null!=n.href?n.type="link":"label"in n&&!("children"in n)&&(n.type="item")),"children"in n&&"submenu"===n.type){const e=n.children;Array.isArray(e)&&(n.children=e.map(le))}return n}function ae(e,n){const t=n.animation;if(!t||t.disabled)return;const o="slide"===t.type?"slide":"fade";e.setAttribute(K,o);const r=t.enter??120,i=t.leave??80,s="number"==typeof r?r:r.duration,l="number"==typeof i?i:i.duration,a="number"==typeof r?"ease-out":r.easing,u="number"==typeof i?"ease-in":i.easing;re(e,{[X]:`${s}ms`,[Y]:`${l}ms`,[U]:a,[Z]:u})}function ue(e,n){const t=document.createElement("span");t.setAttribute("aria-hidden","true"),t.className=g,"string"==typeof n?t.textContent=n:t.appendChild(n),e.appendChild(t)}function ce(e,n){if("string"==typeof n||"number"==typeof n){const t=document.createElement("span");return t.setAttribute("aria-hidden","true"),t.className=R,t.textContent=String(n),void e.appendChild(t)}if(n.render){const t=n.render();return t.getAttribute("aria-hidden")||t.setAttribute("aria-hidden","true"),void e.appendChild(t)}const t=document.createElement("span");t.setAttribute("aria-hidden","true"),t.className=R,n.className&&t.classList.add(...n.className.trim().split(/\s+/)),t.textContent=String(n.content??""),e.appendChild(t)}function de(e,n){const t=document.createElement("span");if(t.setAttribute("aria-hidden","true"),t.className=z,"string"==typeof n){const e=document.createElement("div");for(e.innerHTML=n;e.firstChild;)t.appendChild(e.firstChild)}else t.appendChild(n.cloneNode(!0));e.appendChild(t)}function me(e,n,t,o){const r=document.createElement("span");r.setAttribute("aria-hidden","true"),r.className=N;const i=function(e,n){if(!e||"string"!=typeof e)return null;const t=e.split("+").map(e=>e.trim());if(0===t.length)return null;const o=t[t.length-1]??"",r=t.slice(0,-1).map(e=>e.toLowerCase()),i=o.toLowerCase(),s=ee[i]??(1===o.length?o.toUpperCase():o),l="win"!==n&&("mac"===n||se()),a=l?Q:V;return{mods:r.map(e=>{return{name:e,display:l&&"ctrl"===e?Q.cmd:ee[e]??(n=a[e],t=e,null==n?t:"string"==typeof n?n:n.text)};var n,t}),key:{name:i,display:s},useCmd:l}}(n,o);if(!i)return r.textContent=n,void e.appendChild(r);const{mods:s,key:l,useCmd:a}=i,u=e=>{const n=t?.[e];if(void 0!==n)return n;if("win"===e||"windows"===e){if(a)return;const e=V.win;return"string"==typeof e?void 0:e.icon}};for(const e of s){const n=u(e.name);n?de(r,n):r.appendChild(document.createTextNode(e.display))}const c=u(l.name);c?de(r,c):r.appendChild(document.createTextNode(l.display)),e.appendChild(r)}function pe(e,n,t){const o=document.createElement("span");o.className=E,o.setAttribute("aria-hidden","true"),e.appendChild(o);const r=document.createElement("span");return r.className=A,r.textContent=n,e.appendChild(r),t?.icon&&ue(e,t.icon),t?.shortcut&&me(e,t.shortcut,t.shortcutIcons,t.platform),void 0!==t?.badge&&ce(e,t.badge),o}function fe(e,n,t){ie(e,w),e.setAttribute("aria-busy","true"),function(e,n){const t=e.querySelector(`.${E}`);if(t)Se(t,n);else{const t=document.createElement("span");t.className=E,Se(t,n),e.insertBefore(t,e.querySelector(`.${A}`)??e.firstChild)}}(e,t?.(n)??{})}function he(e,n,t){n&&(e.id=n),t&&e.setAttribute("aria-disabled","true")}function be(e,n,t){const o=e;o[l]=n,t?._cmCheckbox&&(o._cmCheckbox=t._cmCheckbox),t?._cmRadio&&(o._cmRadio=t._cmRadio),t?._cmSubmenu&&(o[a]=t._cmSubmenu)}function ge(e){return e[a]}function ve(e,n,t){const o=o=>{var r;t.onHoverFocus?.(e),t.onEnterParentItem?.(e),t.onItemHoverCallback?.(n,o),"disabled"in n&&n.disabled&&(r=e.closest(W))&&(Ee(r).forEach(e=>e.setAttribute("tabindex","-1")),r.focus()),t.afterFire?.(o)};e.addEventListener("mouseenter",o),e.addEventListener("focus",o),t.onMouseLeave&&e.addEventListener("mouseleave",t.onMouseLeave)}function Ce(e,n){if(null==n)return;const t="function"==typeof n?n():n;for(const[n,o]of Object.entries(t))null!=o&&("function"==typeof o?e.addEventListener(n,o):e.addEventListener(n,o.listener,o.options))}function ye(e){return"number"==typeof e?`${e}px`:e}function Se(e,n){const t=document.createElement("span");t.className=H,t.setAttribute("aria-hidden","true");const o=n.icon;if(null!=o&&void 0!==o)if(t.classList.add(k),"string"==typeof o){const e=document.createElement("div");for(e.innerHTML=o;e.firstChild;)t.appendChild(e.firstChild)}else t.appendChild(o.cloneNode(!0));const r=n.speed??b,i={[x]:`${r}ms`};if(void 0!==n.size){const e=ye(n.size);i.width=e,i.height=e,i.minWidth=e,i.minHeight=e}re(t,i),e.appendChild(t)}function we(e,n,t,o,r,i,s,l,a,u,c,d,m){const p=l??null;if("visible"in e&&!1===e.visible)return null;if("separator"===e.type){const n=document.createElement("div");return n.setAttribute("role","separator"),n.className=y,ie(n,e.className),"events"in e&&e.events&&Ce(n,e.events),n}if("label"===e.type){const n=e,t=document.createElement("div");t.setAttribute("role","presentation"),t.className=`${S} ${T}`,ie(t,n.className),he(t,n.id);const o=document.createElement("span");return o.className=A,o.textContent=n.label,t.appendChild(o),"events"in n&&n.events&&Ce(t,n.events),t}if("checkbox"===e.type||"radio"===e.type)return function(e,n,t){const{close:o,refreshContent:r,getSpinnerOptions:i,onHoverFocus:s,onEnterParentItem:l,onItemHoverCallback:a,shortcutIcons:u,platform:c}=t;let d,m,p,f,h,b,g;if("checkbox"===n?(d="menuitemcheckbox",m=L,p=O,f=I,h={_cmCheckbox:e}):(d="menuitemradio",m=M,p=D,f=F,h={_cmRadio:e}),e.render?b=e.render(e):(b=document.createElement("div"),b.className=`${S} ${m}`,ie(b,e.className,xe(e.variant),e.checked&&P),function(e,n,t,o,r,i,s,l){const a=Boolean(n),u=document.createElement("span");u.setAttribute("aria-hidden","true");const c=null!=t||null!=o;if(u.className=r+(c?` ${i}`:""),a&&s&&u.classList.add(...s.trim().split(/\s+/)),!a&&l&&u.classList.add(...l.trim().split(/\s+/)),c){const e=a?t:o;e&&("string"==typeof e?u.innerHTML=e:u.appendChild(e.cloneNode(!0)))}e.appendChild(u)}(b,e.checked,e.icon,e.uncheckedIcon,p,f,e.checkedClassName,e.uncheckedClassName),pe(b,e.label,{icon:e.leadingIcon,shortcut:e.shortcut,shortcutIcons:u,platform:c})),be(b,e,h),oe(b,{role:d,"aria-checked":e.checked?"true":"false",tabindex:"-1"}),he(b,e.id,e.disabled),e.loading&&fe(b,e,i),ve(b,e,{onHoverFocus:s,onEnterParentItem:l,onItemHoverCallback:a}),Ce(b,e.events),"checkbox"===n){const n=e;g=e=>{n.onChange&&n.onChange({item:n,checked:!n.checked,nativeEvent:e,close:o})}}else{const n=e;g=e=>{n.onSelect&&n.onSelect({item:n,value:n.value,nativeEvent:e,close:o})}}return b.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation(),e.disabled||e.loading||(g(n),r?.(),!1!==e.closeOnAction&&o(e))}),b}(e,e.type,{close:n,refreshContent:a,getSpinnerOptions:c,onHoverFocus:i,onEnterParentItem:s,onItemHoverCallback:u,shortcutIcons:d,platform:m});if("submenu"===e.type){const n=e,l=document.createElement("div");be(l,n,{_cmSubmenu:n}),oe(l,{role:"menuitem","aria-haspopup":"menu","aria-expanded":"false",tabindex:"-1"}),l.className=`${S} ${$}`,ie(l,n.className,xe(n.variant)),he(l,n.id,n.disabled);const a=document.createElement("span");return a.className=A,a.textContent=n.label,l.appendChild(a),n.icon&&ue(l,n.icon),n.shortcut&&me(l,n.shortcut,d,m),void 0!==n.badge&&ce(l,n.badge),p&&function(e,n){const t=document.createElement("span");t.setAttribute("aria-hidden","true"),t.className=v,n.className&&t.classList.add(n.className);const o=n.icon??J,r=n.size??14,i={};void 0!==n.opacity&&(i.opacity=String(n.opacity));const s=ye(r);if(i.width=s,i.height=s,i.minWidth=s,i.minHeight=s,Object.keys(i).length>0&&re(t,i),t.classList.add(C),"string"==typeof o){const e=document.createElement("div");for(e.innerHTML=o;e.firstChild;)t.appendChild(e.firstChild)}else t.appendChild(o.cloneNode(!0));e.appendChild(t)}(l,p),ve(l,n,{onHoverFocus:i,onEnterParentItem:s,onItemHoverCallback:u,afterFire:()=>{n.disabled||(o?o(n,l):t(n,l))},onMouseLeave:r?()=>r(l):void 0}),l.addEventListener("click",e=>{e.preventDefault(),n.disabled||t(n,l)}),Ce(l,n.events),l}if("link"===e.type){const t=e,o=document.createElement("a");return o.className=S,ie(o,t.className,xe(t.variant)),t.disabled||(o.href=t.href,t.target&&(o.target=t.target),t.rel&&(o.rel=t.rel)),pe(o,t.label,{icon:t.icon,shortcut:t.shortcut,badge:t.badge,shortcutIcons:d,platform:m}),be(o,t),oe(o,{role:"menuitem",tabindex:"-1"}),he(o,t.id,t.disabled),t.loading&&fe(o,t,c),ve(o,t,{onHoverFocus:i,onEnterParentItem:s,onItemHoverCallback:u}),o.addEventListener("click",e=>{if(t.disabled||t.loading)return e.preventDefault(),void e.stopPropagation();e.ctrlKey||e.metaKey||(e.preventDefault(),e.stopPropagation(),"_blank"===t.target?window.open(t.href,"_blank",t.rel?`rel=${t.rel}`:void 0):window.location.href=t.href),n(t)}),Ce(o,t.events),o}const f=e;let h;return f.render?h=f.render(f):(h=document.createElement("div"),h.className=S,ie(h,f.className,xe(f.variant)),pe(h,f.label,{icon:f.icon,shortcut:f.shortcut,badge:f.badge,shortcutIcons:d,platform:m})),be(h,f),oe(h,{role:"menuitem",tabindex:"-1"}),he(h,f.id,f.disabled),f.loading&&fe(h,f,c),ve(h,f,{onHoverFocus:i,onEnterParentItem:s,onItemHoverCallback:u}),h.addEventListener("click",e=>{if(e.preventDefault(),e.stopPropagation(),f.disabled||f.loading||!f.onClick)return;const t={item:f,nativeEvent:e,close:n};f.onClick(t),!1!==f.closeOnAction&&n(f)}),Ce(h,f.events),h}function Ee(e){return Array.from(e.querySelectorAll("[role='menuitem']:not([aria-disabled='true']), [role='menuitemcheckbox']:not([aria-disabled='true']), [role='menuitemradio']:not([aria-disabled='true'])"))}function Te(e,n){e.forEach((e,t)=>{e.setAttribute("tabindex",t===n?"0":"-1")}),e[n]&&e[n].focus()}function He(e){return n=>{const t=Ee(e),o=t.indexOf(n);o>=0&&Te(t,o)}}function ke(e){return e.map(e=>{const n={...e};if("children"in n&&"submenu"===n.type){const e=n.children;n.children=Array.isArray(e)?ke(e):e}return n})}function xe(e){return e?`${s}item--${e.trim()}`:null}function Ae(e){return 1===e.length?e.toLowerCase():e}function Le(e,n){const t=e.getAttribute(j);if(t&&t.trim().split(/\s+/).forEach(n=>e.classList.remove(n)),e.removeAttribute(j),n?.class&&(ie(e,...n.class.trim().split(/\s+/).filter(Boolean)),e.setAttribute(j,n.class)),n?.tokens){const t={};for(const[e,o]of Object.entries(n.tokens))t[e.startsWith("--")?e:q+e]=o;re(e,t)}}function Pe(e){e.leaveTimeout&&(clearTimeout(e.leaveTimeout),e.leaveTimeout=null),e.leaveTransitionHandler&&(e.root.removeEventListener("transitionend",e.leaveTransitionHandler),e.leaveTransitionHandler=null),e.root.classList.remove(d)}function Oe(e){ne.delete(e.self),e.openPromiseResolve?.(e.lastSelectedItem),e.openPromiseResolve=null,e.closePromiseResolve?.(),e.closePromiseResolve=null}function Ie(e){const n=e.currentConfig.animation,t=n?.leave??80,o=n?.disabled?0:"number"==typeof t?t:t.duration,r={selectedItem:e.lastSelectedItem,anchor:e.lastAnchor};if(o>0&&!n?.disabled){e.root.classList.remove(c),e.root.classList.add(d);const n=()=>{e.leaveTimeout&&clearTimeout(e.leaveTimeout),e.leaveTimeout=null,e.leaveTransitionHandler&&(e.root.removeEventListener("transitionend",e.leaveTransitionHandler),e.leaveTransitionHandler=null),e.root.classList.remove(d),re(e.root,{display:"none"}),e.wrapper.remove(),Oe(e),e.currentConfig.onClose?.(r),e.currentConfig.onAfterClose?.(r),e.lastFocusTarget&&"function"==typeof e.lastFocusTarget.focus&&e.lastFocusTarget.focus()};e.leaveTransitionHandler=n,e.root.addEventListener("transitionend",n,{once:!0}),e.leaveTimeout=setTimeout(n,o+50)}else re(e.root,{display:"none"}),e.wrapper.remove(),Oe(e),e.currentConfig.onClose?.(r),e.currentConfig.onAfterClose?.(r),e.lastFocusTarget&&"function"==typeof e.lastFocusTarget.focus&&e.lastFocusTarget.focus()}function Ne(e,n,t,o={}){const{clearOpenSubmenu:r=!0,onDone:i}=o,s=t.currentConfig.animation,l=s?.leave??80,a=s?.disabled?0:"number"==typeof l?l:l.duration,u=()=>{if(e.remove(),n.setAttribute("aria-expanded","false"),n.classList.remove(m),r){const n=t.openSubmenus.findIndex(n=>n.panel===e);n>=0&&t.openSubmenus.splice(n,1)}i?.()};if(a<=0||s?.disabled)return void u();e.classList.remove(c),e.classList.add(d);let p=!1;const f=()=>{p||(p=!0,e.removeEventListener("transitionend",f),h&&clearTimeout(h),u())};e.addEventListener("transitionend",f,{once:!0});const h=setTimeout(f,a+50)}function ze(e){return new Promise(n=>{(async()=>{if(!1!==await Promise.resolve(e.currentConfig.onBeforeClose?.()))if(e.isOpen){if(e.closePromiseResolve=n,e.isOpen=!1,e.outsideClickHandler&&(document.removeEventListener("mousedown",e.outsideClickHandler,!0),e.outsideClickHandler=null),e.resizeHandler&&(window.removeEventListener("resize",e.resizeHandler),e.resizeHandler=null),Pe(e),e.submenuHoverTimer&&clearTimeout(e.submenuHoverTimer),e.submenuHoverTimer=null,e.openSubmenus.length>0){const n=e.openSubmenus.slice();e.openSubmenus.length=0;let t=n.length-1;const o=()=>{if(t<0)return void Ie(e);const{panel:r,trigger:i}=n[t];t--,Ne(r,i,e,{clearOpenSubmenu:!1,onDone:o})};return void o()}Ie(e)}else n();else n()})()})}function Re(e,n,t){return new Promise(o=>{e.openPromiseResolve=o,(async()=>{"function"==typeof e.currentConfig.menu&&(e.menu=e.currentConfig.menu().map(le));const o="object"==typeof n&&null!==n?n:void 0;let r,i;if(o)r=o.clientX,i=o.clientY;else if(void 0===n&&void 0===t&&e.currentConfig.getAnchor){const n=function(e){if("width"in e&&"height"in e){const n=e;return{x:n.left+n.width/2,y:n.top}}return e}(e.currentConfig.getAnchor());r=n.x,i=n.y}else r=n??0,i=t??0;const s={x:r,y:i,target:o?.target instanceof Element?o.target:null,event:o};if(!1===await Promise.resolve(e.currentConfig.onBeforeOpen?.(o,s)))return e.openPromiseResolve?.(void 0),void(e.openPromiseResolve=null);ne.add(e.self);const l=[...ne].filter(n=>n!==e.self);await Promise.all(l.map(e=>e.close())),Pe(e),e.isOpen&&await e.realClose(),e.lastAnchor={x:r,y:i},e.lastSelectedItem=void 0,e.lastFocusTarget=document.activeElement,e.isOpen=!0,e.buildRootContent(),e.wrapper.parentElement||e.portal.appendChild(e.wrapper),e.outsideClickHandler=n=>{e.wrapper.contains(n.target)||e.realClose()},document.addEventListener("mousedown",e.outsideClickHandler,!0),e.currentConfig.closeOnResize&&(e.resizeHandler=()=>{e.realClose()},window.addEventListener("resize",e.resizeHandler)),function(e,n,t,o){const r=o.position??{},i=r.offset?.x??0,s=r.offset?.y??0,l=r.padding??8,a=!1!==r.flip,u=!1!==r.shift;re(e,{display:""}),e.getClientRects();const c=e.getBoundingClientRect(),{vw:d,vh:m}=te();let p=n+i,f=t+s;a&&(f+c.height>m-l&&(f=t-c.height-s),p+c.width>d-l&&(p=n-c.width-i),p<l&&(p=l),f<l&&(f=l)),u&&(p=Math.max(l,Math.min(d-c.width-l,p)),f=Math.max(l,Math.min(m-c.height-l,f))),re(e,{left:`${p}px`,top:`${f}px`})}(e.root,r,i,e.currentConfig),re(e.root,{display:""});const a=()=>{e.root.classList.add(c),e.currentConfig.onOpen?.(o);const n=Ee(e.root);n.length&&Te(n,0)},u=e.currentConfig.animation;u?.disabled?a():(e.root.getClientRects(),requestAnimationFrame(a))})()})}function Me(e){e.longPressTimer&&(clearTimeout(e.longPressTimer),e.longPressTimer=null)}function De(e,n){null!=n&&e.boundElement!==n||e.boundElement&&(Me(e),e.boundContextmenu&&e.boundElement.removeEventListener("contextmenu",e.boundContextmenu),e.boundTouchstart&&e.boundElement.removeEventListener("touchstart",e.boundTouchstart),e.boundElement.removeEventListener("touchend",e.boundTouchEndOrCancel),e.boundElement.removeEventListener("touchcancel",e.boundTouchEndOrCancel),e.boundElement=null,e.boundContextmenu=null,e.boundTouchstart=null)}function Fe(e,n,t){De(e);const o=t?.longPressMs??h;e.boundContextmenu=n=>{n.preventDefault(),"pointerType"in n&&"touch"===n.pointerType||Re(e,n)},e.boundTouchstart=n=>{1===n.touches.length&&(Me(e),e.longPressX=n.touches[0].clientX,e.longPressY=n.touches[0].clientY,e.longPressTimer=setTimeout(()=>{e.longPressTimer=null,Re(e,e.longPressX,e.longPressY)},o))},e.boundTouchEndOrCancel=()=>Me(e),n.addEventListener("contextmenu",e.boundContextmenu),n.addEventListener("touchstart",e.boundTouchstart,{passive:!0}),n.addEventListener("touchend",e.boundTouchEndOrCancel,{passive:!0}),n.addEventListener("touchcancel",e.boundTouchEndOrCancel,{passive:!0}),e.boundElement=n}function $e(e,n){e.menu=n.map(le),e.isOpen&&e.buildRootContent()}function _e(e){const n={...e},t=("function"==typeof n.menu?n.menu():n.menu??[]).map(le),o=function(e){return null==e?document.body:"function"==typeof e?e():e}(n.portal),r=document.createElement("div");r.className=_;const i=document.createElement("div");oe(i,{role:"menu","aria-orientation":"vertical",tabindex:"-1"}),i.className=u,re(i,{display:"none",...null!=n.position?.zIndexBase?{zIndex:String(n.position.zIndexBase)}:{}}),Le(i,n.theme),ae(i,n),r.appendChild(i);const s={currentConfig:n,menu:t,portal:o,wrapper:r,root:i,submenuArrowConfig:(d=n.submenuArrow,!1===d||void 0===d?null:!0===d?{icon:J,size:14}:d),isOpen:!1,lastFocusTarget:null,leaveTimeout:null,leaveTransitionHandler:null,openSubmenus:[],submenuHoverTimer:null,outsideClickHandler:null,resizeHandler:null,boundElement:null,boundContextmenu:null,boundTouchstart:null,boundTouchEndOrCancel:()=>{},longPressTimer:null,longPressX:0,longPressY:0,lastAnchor:null,lastSelectedItem:void 0,openPromiseResolve:null,closePromiseResolve:null,self:null,closeWithSelection:null,realClose:null,openSubmenuPanel:null,scheduleSubmenuOpen:null,scheduleSubmenuClose:null,cancelSubmenuClose:null,closeSubmenuWithAnimation:null,buildRootContent:null,refreshContent:null,getSpinnerOptions:null,makeHoverFocusHandler:null,onEnterMenuItem:null,triggerSubmenu:null,_keydownHandler:null};var d;s.self={close:()=>ze(s)},s.closeWithSelection=e=>{void 0!==e&&(s.lastSelectedItem=e),ze(s)},s.realClose=()=>ze(s),s.openSubmenuPanel=(e,n)=>async function(e,n,t){let o=-1;if(e.root.contains(t))o=-1;else for(let n=0;n<e.openSubmenus.length;n++)if(e.openSubmenus[n].panel.contains(t)){o=n;break}for(let n=e.openSubmenus.length-1;n>o;n--){const{panel:t,trigger:o}=e.openSubmenus[n];e.closeSubmenuWithAnimation(t,o,{clearOpenSubmenu:!0})}const r=await async function(e){return(Array.isArray(e)?e:await e()).map(le)}(n.children),i=document.createElement("div");oe(i,{role:"menu","aria-label":n.label,"aria-orientation":"vertical",tabindex:"-1"}),i.className=`${u} ${B}`,i.addEventListener("mouseenter",e.cancelSubmenuClose),Le(i,e.currentConfig.theme),ae(i,e.currentConfig);const s=e.currentConfig.position?.submenuZIndexStep??0,l=e.currentConfig.position?.zIndexBase??9999;s>0&&re(i,{zIndex:String(l+(e.openSubmenus.length+1)*s)}),r.forEach(n=>{const t=we(n,e.closeWithSelection,(n,t)=>{e.openSubmenuPanel(n,t)},e.scheduleSubmenuOpen,e.scheduleSubmenuClose,e.makeHoverFocusHandler(i),e.onEnterMenuItem,e.submenuArrowConfig,e.refreshContent,(n,t)=>e.currentConfig.onItemHover?.({item:n,nativeEvent:t}),e.getSpinnerOptions,e.currentConfig.shortcutIcons,e.currentConfig.platform);t&&i.appendChild(t)}),e.wrapper.appendChild(i);const a=t.getBoundingClientRect(),d=e.currentConfig.position?.padding??8,{vw:p,vh:f}=te(),h="rtl"===getComputedStyle(t).direction,b=n.submenuPlacement??e.currentConfig.submenuPlacement??"auto";re(i,{display:""}),i.getClientRects();const g=i.getBoundingClientRect();let v;"left"===b?(v=a.left-g.width-2,v<d&&(v=a.right+2)):"right"===b?(v=a.right+2,v+g.width>p-d&&(v=a.left-g.width-2)):h?(v=a.left-g.width-2,v<d&&(v=a.right+2)):(v=a.right+2,v+g.width>p-d&&(v=a.left-g.width-2));let C=a.top;C+g.height>f-d&&(C=f-g.height-d),C<d&&(C=d),re(i,{left:`${v}px`,top:`${C}px`}),t.setAttribute("aria-expanded","true"),t.classList.add(m),e.openSubmenus.push({panel:i,trigger:t}),requestAnimationFrame(()=>i.classList.add(c))}(s,e,n),s.scheduleSubmenuOpen=(e,n)=>function(e,n,t){const o=e.openSubmenus[e.openSubmenus.length-1];o&&o.trigger===t?t.focus():(e.submenuHoverTimer&&clearTimeout(e.submenuHoverTimer),e.submenuHoverTimer=setTimeout(()=>{e.submenuHoverTimer=null;const o=e.openSubmenus[e.openSubmenus.length-1];o&&o.trigger===t||e.openSubmenuPanel(n,t)},p))}(s,e,n),s.scheduleSubmenuClose=e=>function(e,n){e.submenuHoverTimer&&clearTimeout(e.submenuHoverTimer),e.submenuHoverTimer=setTimeout(()=>{e.submenuHoverTimer=null;const t=e.openSubmenus.findIndex(e=>e.trigger===n);if(!(t<0))for(let n=e.openSubmenus.length-1;n>=t;n--){const{panel:t,trigger:o}=e.openSubmenus[n];e.closeSubmenuWithAnimation(t,o,{clearOpenSubmenu:!0})}},f)}(s,e),s.cancelSubmenuClose=()=>function(e){e.submenuHoverTimer&&clearTimeout(e.submenuHoverTimer),e.submenuHoverTimer=null}(s),s.closeSubmenuWithAnimation=(e,n,t)=>Ne(e,n,s,t),s.buildRootContent=()=>function(e){e.root.innerHTML="",e.menu.forEach(n=>{const t=we(n,e.closeWithSelection,e.triggerSubmenu,e.scheduleSubmenuOpen,e.scheduleSubmenuClose,e.makeHoverFocusHandler(e.root),n=>e.onEnterMenuItem(n),e.submenuArrowConfig,e.refreshContent,(n,t)=>e.currentConfig.onItemHover?.({item:n,nativeEvent:t}),e.getSpinnerOptions,e.currentConfig.shortcutIcons,e.currentConfig.platform);t&&e.root.appendChild(t)})}(s),s.refreshContent=()=>function(e){e.isOpen&&"function"==typeof e.currentConfig.menu&&(e.menu=e.currentConfig.menu().map(le),e.buildRootContent())}(s),s.getSpinnerOptions=e=>function(e,n){const t=e.currentConfig.spinner??{};return n&&"object"==typeof n&&("loadingIcon"in n||"loadingSize"in n||"loadingSpeed"in n)?{...t,..."loadingIcon"in n&&void 0!==n.loadingIcon&&{icon:n.loadingIcon},..."loadingSize"in n&&void 0!==n.loadingSize&&{size:n.loadingSize},..."loadingSpeed"in n&&void 0!==n.loadingSpeed&&{speed:n.loadingSpeed}}:t}(s,e),s.makeHoverFocusHandler=He,s.onEnterMenuItem=e=>function(e,n){if(0===e.openSubmenus.length)return;e.cancelSubmenuClose();const t=n.closest(W);if(!t)return;let o=-1;if(t!==e.root)for(let n=0;n<e.openSubmenus.length;n++)if(e.openSubmenus[n].panel===t){o=n;break}for(let n=e.openSubmenus.length-1;n>o;n--){const{panel:t,trigger:o}=e.openSubmenus[n];e.closeSubmenuWithAnimation(t,o,{clearOpenSubmenu:!0})}}(s,e),s.triggerSubmenu=(e,n)=>{s.openSubmenuPanel(e,n)},s._keydownHandler=e=>function(e,n){const t=n.target,o=t.closest(W);if(!o)return;const r=o.classList.contains(B),i=Ee(o);let s=i.indexOf(t);if(-1!==s)switch(n.key){case"ArrowDown":n.preventDefault(),Te(i,(s+1)%i.length);break;case"ArrowUp":n.preventDefault(),Te(i,0===s?i.length-1:s-1);break;case"ArrowRight":{n.preventDefault();const o=ge(t);o&&e.openSubmenuPanel(o,t);break}case"ArrowLeft":if(n.preventDefault(),r&&e.openSubmenus.length>0){const{panel:n,trigger:t}=e.openSubmenus[e.openSubmenus.length-1];e.closeSubmenuWithAnimation(n,t,{clearOpenSubmenu:!0,onDone:()=>t.focus()})}else e.realClose();break;case"Enter":case" ":{n.preventDefault();const o=ge(t);o?e.openSubmenuPanel(o,t):t.click();break}case"Escape":if(n.preventDefault(),r&&e.openSubmenus.length>0){const{panel:n,trigger:t}=e.openSubmenus[e.openSubmenus.length-1];e.closeSubmenuWithAnimation(n,t,{clearOpenSubmenu:!0,onDone:()=>t.focus()})}else e.realClose();break;case"Home":n.preventDefault(),Te(i,0);break;case"End":n.preventDefault(),Te(i,i.length-1);break;default:{const t=i.find(e=>{const t=function(e){const n=e;return n[a]??n[l]}(e);return!!(t&&"shortcut"in t&&t.shortcut)&&function(e,n){const t=e.split("+").map(e=>e.trim()).filter(Boolean);if(0===t.length)return!1;if(Ae(t[t.length-1]??"")!==Ae(n.key))return!1;const o=t.slice(0,-1).map(e=>e.toLowerCase());if(o.includes("ctrl")||o.includes("cmd")){if(!(se()?n.metaKey&&!n.ctrlKey:n.ctrlKey&&!n.metaKey))return!1}else if(n.ctrlKey||n.metaKey)return!1;const r=(e,n)=>o.includes(e)?n:!n;return!!r("alt",n.altKey)&&!!r("shift",n.shiftKey)}(t.shortcut,n)});if(t){n.preventDefault();const o=ge(t);o?(e.openSubmenuPanel(o,t),requestAnimationFrame(()=>{const n=e.openSubmenus[e.openSubmenus.length-1];if(!n)return;const t=Ee(n.panel);t.length&&Te(t,0)})):t.click()}break}}else"ArrowDown"===n.key&&i.length?(n.preventDefault(),Te(i,0)):"ArrowUp"===n.key&&i.length&&(n.preventDefault(),Te(i,i.length-1))}(s,e),r.addEventListener("keydown",s._keydownHandler);const h=n.bind;if(null!=h){const e=h instanceof HTMLElement?h:h.element;Fe(s,e,h instanceof HTMLElement?void 0:h.options)}return function(e){return{open:(n,t)=>Re(e,n,t),close:()=>e.realClose(),toggle(n,t){e.isOpen?e.realClose():Re(e,n??0,t??0)},openAtElement:(n,t)=>function(e,n,t){const o=t?.offset??{x:0,y:0},r=n.getBoundingClientRect();let i,s,l=t?.placement??"bottom-start";if("auto"===l){const t=e.currentConfig.position?.padding??8,{vw:o,vh:i}=te(),s=r.top-t,a=i-r.bottom-t,u=r.left-t,c=o-r.right-t,d=a>=s?"bottom":"top",m="rtl"===getComputedStyle(n).direction;l=`${d}-${(m?u:c)>=(m?c:u)?m?"end":"start":m?"start":"end"}`}switch(l){case"bottom-start":case"left-end":default:i=r.left,s=r.bottom;break;case"bottom-end":case"right-end":i=r.right,s=r.bottom;break;case"top-start":case"left-start":i=r.left,s=r.top;break;case"top-end":case"right-start":i=r.right,s=r.top}Re(e,i+o.x,s+o.y)}(e,n,t),isOpen:()=>e.isOpen,getAnchor:()=>e.lastAnchor,getMenu:()=>ke(e.menu),getRootElement:()=>e.wrapper,updateMenu:n=>$e(e,n(ke(e.menu))),bind:(n,t)=>Fe(e,n,t),unbind:n=>De(e,n),destroy:()=>function(e){De(e),e.outsideClickHandler&&(document.removeEventListener("mousedown",e.outsideClickHandler,!0),e.outsideClickHandler=null),e.resizeHandler&&(window.removeEventListener("resize",e.resizeHandler),e.resizeHandler=null),e.leaveTimeout&&clearTimeout(e.leaveTimeout),e.submenuHoverTimer&&clearTimeout(e.submenuHoverTimer),e.wrapper.remove(),e.wrapper.removeEventListener("keydown",e._keydownHandler)}(e),setMenu:n=>$e(e,n),setTheme:n=>function(e,n){e.currentConfig.theme=n,Le(e.root,n);for(const{panel:t}of e.openSubmenus)Le(t,n)}(e,n),setPosition:n=>function(e,n){e.currentConfig.position=n}(e,n),setAnimation:n=>function(e,n){e.currentConfig.animation=n,ae(e.root,e.currentConfig);for(const{panel:n}of e.openSubmenus)ae(n,e.currentConfig)}(e,n)}}(s)}//# sourceMappingURL=index.cjs.map