efficient-shell 0.0.0-stage → 4.126.2
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 +21 -0
- package/README.md +753 -2
- package/dist/Browser-DBRSIQ4J.js +478 -0
- package/dist/Browser-DBRSIQ4J.js.map +1 -0
- package/dist/Calculator-HCKFTSJR.js +188 -0
- package/dist/Calculator-HCKFTSJR.js.map +1 -0
- package/dist/ConfirmDialog-LJXMB45A.js +3 -0
- package/dist/ConfirmDialog-LJXMB45A.js.map +1 -0
- package/dist/CurrencyConverter-BKKORN6K.js +232 -0
- package/dist/CurrencyConverter-BKKORN6K.js.map +1 -0
- package/dist/Documents-5MD5SKPB.js +437 -0
- package/dist/Documents-5MD5SKPB.js.map +1 -0
- package/dist/Files-KY35DPWB.js +801 -0
- package/dist/Files-KY35DPWB.js.map +1 -0
- package/dist/Notepad-2BO5VEUG.js +406 -0
- package/dist/Notepad-2BO5VEUG.js.map +1 -0
- package/dist/PdfViewer-LSP3YNFC.js +4 -0
- package/dist/PdfViewer-LSP3YNFC.js.map +1 -0
- package/dist/PomodoroTimer-SVJ62RXM.js +629 -0
- package/dist/PomodoroTimer-SVJ62RXM.js.map +1 -0
- package/dist/Preview-N4UYYXG6.js +2955 -0
- package/dist/Preview-N4UYYXG6.js.map +1 -0
- package/dist/Sidebar-J76PV4QF.js +290 -0
- package/dist/Sidebar-J76PV4QF.js.map +1 -0
- package/dist/Spreadsheet-5EWZGMXN.js +515 -0
- package/dist/Spreadsheet-5EWZGMXN.js.map +1 -0
- package/dist/Stock-CDUS4VCZ.js +154 -0
- package/dist/Stock-CDUS4VCZ.js.map +1 -0
- package/dist/Weather-EEDBWBPQ.js +427 -0
- package/dist/Weather-EEDBWBPQ.js.map +1 -0
- package/dist/WorldClock-FFFULVTJ.js +198 -0
- package/dist/WorldClock-FFFULVTJ.js.map +1 -0
- package/dist/apps/index.d.ts +267 -0
- package/dist/apps/index.js +147 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/brand.css +2 -0
- package/dist/chunk-2VM2FRZJ.js +215 -0
- package/dist/chunk-2VM2FRZJ.js.map +1 -0
- package/dist/chunk-32W6VY2J.js +549 -0
- package/dist/chunk-32W6VY2J.js.map +1 -0
- package/dist/chunk-3CUSBZWG.js +59 -0
- package/dist/chunk-3CUSBZWG.js.map +1 -0
- package/dist/chunk-3L463T5H.js +26 -0
- package/dist/chunk-3L463T5H.js.map +1 -0
- package/dist/chunk-4TVV2BIU.js +13334 -0
- package/dist/chunk-4TVV2BIU.js.map +1 -0
- package/dist/chunk-6XQHH7D2.js +105 -0
- package/dist/chunk-6XQHH7D2.js.map +1 -0
- package/dist/chunk-7CCHEEYC.js +94 -0
- package/dist/chunk-7CCHEEYC.js.map +1 -0
- package/dist/chunk-7KIOEKHS.js +617 -0
- package/dist/chunk-7KIOEKHS.js.map +1 -0
- package/dist/chunk-AXWC3332.js +1103 -0
- package/dist/chunk-AXWC3332.js.map +1 -0
- package/dist/chunk-BFBWLCO6.js +16 -0
- package/dist/chunk-BFBWLCO6.js.map +1 -0
- package/dist/chunk-C3NELUTX.js +79 -0
- package/dist/chunk-C3NELUTX.js.map +1 -0
- package/dist/chunk-CT3HVZRZ.js +26 -0
- package/dist/chunk-CT3HVZRZ.js.map +1 -0
- package/dist/chunk-D7PYW2QS.js +265 -0
- package/dist/chunk-D7PYW2QS.js.map +1 -0
- package/dist/chunk-DMCFOWOJ.js +153 -0
- package/dist/chunk-DMCFOWOJ.js.map +1 -0
- package/dist/chunk-FQB24B42.js +416 -0
- package/dist/chunk-FQB24B42.js.map +1 -0
- package/dist/chunk-GA35NEND.js +56 -0
- package/dist/chunk-GA35NEND.js.map +1 -0
- package/dist/chunk-HNH7FOYB.js +69 -0
- package/dist/chunk-HNH7FOYB.js.map +1 -0
- package/dist/chunk-HYZ5QMVO.js +462 -0
- package/dist/chunk-HYZ5QMVO.js.map +1 -0
- package/dist/chunk-I464GYJJ.js +17 -0
- package/dist/chunk-I464GYJJ.js.map +1 -0
- package/dist/chunk-JFQGPY7W.js +819 -0
- package/dist/chunk-JFQGPY7W.js.map +1 -0
- package/dist/chunk-MGGY74RY.js +14 -0
- package/dist/chunk-MGGY74RY.js.map +1 -0
- package/dist/chunk-N3CG5HG5.js +144 -0
- package/dist/chunk-N3CG5HG5.js.map +1 -0
- package/dist/chunk-W6XTG23K.js +3708 -0
- package/dist/chunk-W6XTG23K.js.map +1 -0
- package/dist/chunk-YG45DAUT.js +96 -0
- package/dist/chunk-YG45DAUT.js.map +1 -0
- package/dist/chunk-YMGXZABY.js +7 -0
- package/dist/chunk-YMGXZABY.js.map +1 -0
- package/dist/chunk-YNGPTOL6.js +46 -0
- package/dist/chunk-YNGPTOL6.js.map +1 -0
- package/dist/chunk-YNHLQ24V.js +400 -0
- package/dist/chunk-YNHLQ24V.js.map +1 -0
- package/dist/chunk-YNKK7NE3.js +171 -0
- package/dist/chunk-YNKK7NE3.js.map +1 -0
- package/dist/chunk-YPO6RDMX.js +20 -0
- package/dist/chunk-YPO6RDMX.js.map +1 -0
- package/dist/file-intake/index.d.ts +87 -0
- package/dist/file-intake/index.js +3 -0
- package/dist/file-intake/index.js.map +1 -0
- package/dist/index-dQia6NpB.d.ts +5904 -0
- package/dist/index.d.ts +2495 -0
- package/dist/index.js +7460 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown/index.d.ts +118 -0
- package/dist/markdown/index.js +184 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markup/index.d.ts +235 -0
- package/dist/markup/index.js +135 -0
- package/dist/markup/index.js.map +1 -0
- package/dist/page-tabs/index.d.ts +154 -0
- package/dist/page-tabs/index.js +706 -0
- package/dist/page-tabs/index.js.map +1 -0
- package/dist/shell.css +105 -0
- package/dist/sounds-NT4DEZGD.js +3 -0
- package/dist/sounds-NT4DEZGD.js.map +1 -0
- package/dist/styles.css +22 -0
- package/dist/themes.css +249 -0
- package/dist/types-BOinJXUf.d.ts +118 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui.css +1518 -0
- package/package.json +178 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shell/strings.tsx","../src/shell/contextMenuTarget.ts","../src/shell/menuPath.ts","../src/shell/PopupMenu.tsx"],"names":["createContext","useMemo","jsx","PopupMenuItem","useContext"],"mappings":"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","file":"chunk-7KIOEKHS.js","sourcesContent":["/**\n * ShellStrings — the shell's user-facing strings, in one typed catalog.\n *\n * Every string here was hardcoded English at its call site, which made the\n * shell untranslatable no matter what the consuming portal did. The catalog\n * is the fix's whole shape: components read strings through `useShellStrings`\n * (which works with NO provider — the English defaults are the context\n * default), and a consumer that wants another language mounts\n * `ShellStringsProvider` once with a partial override. Overrides merge per\n * SECTION, so translating the window controls does not oblige anyone to\n * translate the help viewer.\n *\n * This is deliberately not an i18n library: no message IDs, no interpolation\n * DSL, no plural rules. The shell's strings are labels and short sentences;\n * a typed object keeps them discoverable and lets TypeScript flag a\n * translation that goes stale when a string is added.\n *\n * Prop-level text (a `emptyText` prop, a `placeholder`) always wins over the\n * catalog — the catalog replaces hardcoded DEFAULTS, never a caller's words.\n *\n * Kit-safe: no window-manager import, so `react-os-shell/ui` consumers get it\n * too.\n */\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\n\nexport interface ShellStrings {\n /** Window chrome: control tooltips and the title bar's accessible name. */\n window: {\n minimize: string;\n /** Bring a hand-minimized window back — the tab's own control. */\n restore: string;\n maximize: string;\n windowed: string;\n pinOnTop: string;\n unpin: string;\n close: string;\n /** Suffix of the title bar's aria-label: `\"{title} — {windowSuffix}\"`. */\n windowSuffix: string;\n prev: string;\n next: string;\n snapLayouts: string;\n snapLeft: string;\n snapRight: string;\n snapTopLeft: string;\n snapTopRight: string;\n snapBottomLeft: string;\n snapBottomRight: string;\n };\n /** Taskbar and exposé. */\n taskbar: {\n closeWindow: string;\n offscreenHint: string;\n offscreenDot: string;\n expose: string;\n addToDesktop: string;\n removeFromDesktop: string;\n /** Group menu — a taskbar tab standing for more than one window. The\n * count is appended by the caller, e.g. \"Close all (3)\". */\n minimizeAllWindows: string;\n restoreAllWindows: string;\n closeAllWindows: string;\n };\n /** The logout cover. */\n logout: {\n goodbye: string;\n seeYou: string;\n };\n /** About + What's New dialogs. */\n about: {\n aboutPrefix: string;\n thisApp: string;\n openSourceLicenses: string;\n whatsNew: string;\n noChangelog: string;\n };\n /** Data-display defaults (DataTable, lists). */\n table: {\n empty: string;\n loading: string;\n selectAll: string;\n selectRow: string;\n };\n /** Picker defaults (SearchableSelect, TagInput). */\n select: {\n none: string;\n noMatches: string;\n allSelected: string;\n clear: string;\n /** aria-label of a TagInput chip's remove button: `\"{remove} {label}\"`. */\n remove: string;\n };\n /** Notification bell + popup. */\n notifications: {\n title: string;\n markAllRead: string;\n dnd: string;\n dndOn: string;\n caughtUp: string;\n empty: string;\n viewAll: string;\n cardLabel: string;\n dismiss: string;\n };\n /** Form-level messages. */\n form: {\n errorSummaryTitle: string;\n };\n /** HelpCenter chrome. */\n help: {\n title: string;\n searchPlaceholder: string;\n empty: string;\n noResults: string;\n loading: string;\n pickArticle: string;\n noBody: string;\n draft: string;\n newArticle: string;\n edit: string;\n };\n /** The app-update banner (a deploy happened under a long-lived tab). */\n update: {\n available: string;\n refreshNow: string;\n };\n /** The page-tab strip (`react-os-shell/page-tabs`). */\n pageTabs: {\n /** The strip's accessible name. */\n label: string;\n /** A tab's close button, and the menu item: `\"{close} {title}\"` for the button. */\n close: string;\n closeOthers: string;\n closeRight: string;\n closeAll: string;\n /** Marks a tab with unsaved changes (the dot's accessible text). */\n unsaved: string;\n /** Asked before a tab with unsaved changes closes. */\n discardTitle: string;\n discardOne: string;\n /** Several at once — the count is prefixed by the caller: \"3 pages have…\". */\n discardMany: string;\n discardConfirm: string;\n keepEditing: string;\n };\n}\n\nexport const DEFAULT_SHELL_STRINGS: ShellStrings = {\n window: {\n minimize: 'Minimize',\n restore: 'Restore',\n maximize: 'Maximize',\n windowed: 'Windowed',\n pinOnTop: 'Pin on top',\n unpin: 'Unpin from top',\n close: 'Close',\n windowSuffix: 'window',\n prev: 'Prev',\n next: 'Next',\n snapLayouts: 'Snap layouts',\n snapLeft: 'Snap left half',\n snapRight: 'Snap right half',\n snapTopLeft: 'Snap top-left quarter',\n snapTopRight: 'Snap top-right quarter',\n snapBottomLeft: 'Snap bottom-left quarter',\n snapBottomRight: 'Snap bottom-right quarter',\n },\n taskbar: {\n closeWindow: 'Close window',\n offscreenHint: 'This window is off screen — click to bring it back',\n offscreenDot: 'Off screen — click to bring this window back',\n expose: 'Exposé — show all open windows as thumbnails',\n addToDesktop: 'Add to desktop',\n removeFromDesktop: 'Remove from desktop',\n minimizeAllWindows: 'Minimize all',\n restoreAllWindows: 'Restore all',\n closeAllWindows: 'Close all',\n },\n logout: {\n goodbye: 'Goodbye',\n seeYou: 'See you next time',\n },\n about: {\n aboutPrefix: 'About',\n thisApp: 'this app',\n openSourceLicenses: 'Open Source Licenses',\n whatsNew: \"What's New\",\n noChangelog: 'No changelog available.',\n },\n table: {\n empty: 'Nothing to show',\n loading: 'Loading',\n selectAll: 'Select all rows',\n selectRow: 'Select row',\n },\n select: {\n none: '— None —',\n noMatches: 'No matches',\n allSelected: 'All options selected',\n clear: 'Clear selection',\n remove: 'Remove',\n },\n notifications: {\n title: 'Notifications',\n markAllRead: 'Mark all read',\n dnd: 'Do not disturb',\n dndOn: 'Do not disturb is on',\n caughtUp: 'All caught up',\n empty: 'No notifications yet',\n viewAll: 'View all notifications',\n cardLabel: 'Notification',\n dismiss: 'Dismiss notification',\n },\n form: {\n errorSummaryTitle: 'There is a problem',\n },\n help: {\n title: 'Help',\n searchPlaceholder: 'Search help…',\n empty: 'No help articles yet.',\n noResults: 'No articles match your search.',\n loading: 'Loading…',\n pickArticle: 'Pick a help article from the left.',\n noBody: 'This article has no body yet.',\n draft: 'Draft',\n newArticle: '+ New',\n edit: 'Edit',\n },\n update: {\n available: 'A new version is available.',\n refreshNow: 'Refresh now',\n },\n pageTabs: {\n label: 'Open pages',\n close: 'Close',\n closeOthers: 'Close other tabs',\n closeRight: 'Close tabs to the right',\n closeAll: 'Close all tabs',\n unsaved: 'Unsaved changes',\n discardTitle: 'Discard unsaved changes?',\n discardOne: 'This page has changes that have not been saved. Close it anyway?',\n discardMany: 'pages have changes that have not been saved. Close them anyway?',\n discardConfirm: 'Discard and close',\n keepEditing: 'Keep editing',\n },\n};\n\n/** A per-section partial: override any subset of a section's strings. */\nexport type ShellStringsOverride = {\n [S in keyof ShellStrings]?: Partial<ShellStrings[S]>;\n};\n\nconst ShellStringsContext = createContext<ShellStrings>(DEFAULT_SHELL_STRINGS);\n\n/**\n * Mount once, near the top of the app. `value` is a partial — sections and\n * keys you do not translate keep their English defaults, so a catalog never\n * breaks by falling behind a release.\n */\nexport function ShellStringsProvider({ value, children }: { value: ShellStringsOverride; children: ReactNode }) {\n const merged = useMemo<ShellStrings>(() => {\n const out = {} as ShellStrings;\n for (const key of Object.keys(DEFAULT_SHELL_STRINGS) as (keyof ShellStrings)[]) {\n out[key] = { ...DEFAULT_SHELL_STRINGS[key], ...(value[key] ?? {}) } as never;\n }\n return out;\n }, [value]);\n return <ShellStringsContext.Provider value={merged}>{children}</ShellStringsContext.Provider>;\n}\n\n/** The active catalog — English defaults when no provider is mounted. */\nexport function useShellStrings(): ShellStrings {\n return useContext(ShellStringsContext);\n}\n","/**\n * What the shell's global context menu should offer for a given right-click.\n *\n * Kept free of React (and of the DOM beyond the element it is handed) so the\n * two rules that matter can be tested directly: which targets keep the\n * browser's own menu, and which items a click produces.\n */\n\n/** Input types that put a text caret on screen. Everything else — a checkbox,\n * a range, a color swatch, a file button — has no spellcheck and no Paste,\n * so there is nothing in the browser's menu worth keeping for it. */\nconst TEXT_INPUT_TYPES = new Set([\n 'text', 'search', 'url', 'tel', 'email', 'password', 'number',\n 'date', 'datetime-local', 'month', 'week', 'time',\n]);\n\n/** Elements whose browser menu does what a page cannot: Save image as and Copy\n * image — the picture itself, not its address — on an image or a canvas, and\n * the playback controls on video and audio. */\nconst NATIVE_MEDIA = 'img, picture, canvas, video, audio';\n\n/** Opt-out attribute: anything inside `[data-native-context-menu]` keeps the\n * browser's menu. For surfaces the shell has no business re-skinning — an\n * embedded viewer, a third-party widget. */\nexport const NATIVE_MENU_ATTR = 'data-native-context-menu';\n\nfunction closest(el: Element | null, selector: string): Element | null {\n if (!el || typeof (el as Element).closest !== 'function') return null;\n return el.closest(selector);\n}\n\n/**\n * Does this target keep the browser's native menu?\n *\n * Text inputs, textareas and contenteditable do, deliberately: the browser's\n * spellcheck suggestions and \"Add to dictionary\" cannot be rebuilt by a web\n * page, and a Paste item of our own would need a clipboard permission prompt.\n * Images, canvases and media do for the same reason — Save / Copy image and\n * the playback controls are the browser's. The shell menu is for everywhere\n * else.\n */\nexport function keepsNativeMenu(target: EventTarget | null): boolean {\n const el = target as Element | null;\n if (!el || typeof (el as Element).closest !== 'function') return false;\n\n if (closest(el, `[${NATIVE_MENU_ATTR}]`)) return true;\n if (closest(el, 'textarea')) return true;\n if (closest(el, NATIVE_MEDIA)) return true;\n\n const input = closest(el, 'input') as HTMLInputElement | null;\n if (input) {\n // The property, not the attribute: the browser normalizes it, so a type it\n // does not recognise (`type=\"currency\"`, a typo) reads as the text box it\n // actually renders.\n const type = (input.type || 'text').toLowerCase();\n if (TEXT_INPUT_TYPES.has(type)) return true;\n }\n\n // `isContentEditable` is the property to ask, but jsdom does not implement\n // it, so walk the attribute — which is also what the nesting rules are\n // written in (`contenteditable=\"false\"` re-enables our menu inside an\n // editable region).\n const editable = closest(el, '[contenteditable]');\n if (editable) {\n const value = (editable.getAttribute('contenteditable') || '').toLowerCase();\n if (value === '' || value === 'true' || value === 'plaintext-only') return true;\n }\n\n return false;\n}\n\nexport type ShellContextKind = 'selection' | 'link' | 'default';\n\nexport interface ShellContextTarget {\n /** The most specific thing under the pointer — what the menu leads with. */\n kind: ShellContextKind;\n /** Trimmed selection text, when something is selected. */\n selectionText?: string;\n /** Absolute href of the nearest enclosing link. */\n linkUrl?: string;\n}\n\n/** Schemes worth an Open / Copy link address. A `javascript:` URL is a button\n * wearing a link's clothes, and `href=\"#\"` is the same trick. */\nconst LINK_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:', 'blob:']);\n\nfunction linkAddress(href: string | null | undefined, base?: string): string | undefined {\n if (!href || href === '#') return undefined;\n try {\n // `document.baseURI`, not `location.href`: a page with a `<base>` resolves\n // this the way its own links do.\n const url = new URL(href, base ?? (typeof document !== 'undefined' ? document.baseURI : undefined));\n return LINK_SCHEMES.has(url.protocol) ? url.href : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Describe a right-click: what was under the pointer, and what is selected.\n *\n * A selection inside a link reports both, so the menu can offer both sections\n * the way a browser's does; `kind` names whichever the menu should lead with.\n */\nexport function describeContextTarget(\n target: EventTarget | null,\n selectionText?: string | null,\n baseUrl?: string,\n): ShellContextTarget {\n const el = target as Element | null;\n const link = closest(el, 'a[href]');\n\n const text = (selectionText || '').trim();\n const linkUrl = linkAddress(link?.getAttribute('href'), baseUrl);\n\n const kind: ShellContextKind = text ? 'selection' : linkUrl ? 'link' : 'default';\n\n return {\n kind,\n ...(text ? { selectionText: text } : {}),\n ...(linkUrl ? { linkUrl } : {}),\n };\n}\n","/**\n * The open-submenu path of a hover menu — the whole state machine <StartMenu>\n * uses to decide which flyouts are open, at any depth.\n *\n * ## Why this exists\n *\n * The menu used to have TWO mechanisms: one that opened a section's flyout\n * (`hoveredSection` + its timer) and a second, separately written one that\n * opened a flyout under an item inside that flyout (`hoveredChild` + its own\n * timer). They looked alike but behaved differently, and the second one had\n * the bugs — a stale close-timer from a sibling row could fire *after* a\n * submenu had opened and shut it under the cursor, which is what \"the next\n * level is slow, or sometimes doesn't open at all\" actually was. There was\n * also no third mechanism, so a 4th level simply never rendered.\n *\n * One path, one set of rules, any depth. Panels are numbered from the root\n * menu: panel 0 is the menu itself, and `path[i]` is the row that opened panel\n * `i + 1`. So `path.length` is the number of open flyouts, and closing\n * everything under panel `d` is just truncating the path to `d`.\n *\n * All of it is pure: hover geometry comes in as numbers, so the rules can be\n * tested without a DOM.\n */\n\n/** One open flyout: which row opened it, and where it goes. */\nexport interface MenuAnchor {\n /** Identity of the row that opened this panel — a section label or an item\n * route. Also what marks that row as the open one. */\n key: string;\n /** Viewport Y of the opening row's centre; the panel is centred on it. */\n y: number;\n /** Viewport X of the panel's left edge. Resolved when the row is hovered,\n * because it depends on where the panel that owns the row ended up. */\n left: number;\n /** Whether this panel had to open to the LEFT of the one that owns its row.\n * Carried so the next level down can keep going the same way. */\n flipped: boolean;\n}\n\n/**\n * Open `anchor` as the submenu of a row in panel `depth`, closing anything\n * deeper (the previous branch the user was down).\n *\n * Returns the SAME array when that panel is already open for that key and\n * nothing deeper is open, so a repeated `mouseenter` on a row the user is\n * already on can't re-render the menu — and can't reset the panel's open\n * animation.\n */\nexport function openMenuLevel(path: MenuAnchor[], depth: number, anchor: MenuAnchor): MenuAnchor[] {\n if (path.length === depth + 1 && path[depth].key === anchor.key) return path;\n return [...path.slice(0, depth), anchor];\n}\n\n/**\n * Close panel `depth + 1` and everything under it — what hovering a row with\n * no submenu, or leaving a panel, eventually leads to.\n *\n * Also identity-stable: nothing to close means the same array back.\n */\nexport function closeMenuBelow(path: MenuAnchor[], depth: number): MenuAnchor[] {\n const keep = Math.max(0, depth);\n return path.length > keep ? path.slice(0, keep) : path;\n}\n\n/**\n * The items each open panel shows: `[0]` is the flyout the root row opened,\n * `[1]` its child, and so on for as long as the path keeps resolving.\n *\n * Stops early rather than rendering an empty panel, so a path left over from a\n * branch that has since disappeared (a permission change, nav data swapped\n * under the menu) degrades to the levels that still exist.\n */\nexport function resolveMenuLevels<T extends { to: string }>(\n rootItems: T[],\n path: MenuAnchor[],\n childrenOf: (item: T) => T[],\n): T[][] {\n if (path.length === 0 || rootItems.length === 0) return [];\n const levels: T[][] = [rootItems];\n for (let i = 1; i < path.length; i++) {\n const parent = levels[i - 1].find(item => item.to === path[i].key);\n const kids = parent ? childrenOf(parent) : [];\n if (kids.length === 0) break;\n levels.push(kids);\n }\n return levels;\n}\n\n/**\n * Where a panel of height `height` sits when centred on `anchorY`, kept inside\n * the usable vertical span (`minTop`..`maxBottom` — the viewport minus the\n * taskbar edge and a gutter).\n *\n * A panel taller than the span is pinned to the top of it and scrolls; that is\n * why the height is clamped before it is centred, and not after.\n */\nexport function clampMenuTop(anchorY: number, height: number, minTop: number, maxBottom: number): number {\n const span = Math.max(0, maxBottom - minTop);\n const h = Math.min(height, span);\n const top = anchorY - h / 2;\n if (top < minTop) return minTop;\n if (top + h > maxBottom) return Math.max(minTop, maxBottom - h);\n return top;\n}\n\n/**\n * Where a panel of width `width` sits horizontally: to the right of the panel\n * that owns the hovered row, or flipped to its left when there isn't room.\n *\n * The flip is what makes depth open-ended. Every level costs another panel\n * width, so a deep enough branch always runs out of screen — and a menu opened\n * from a right-hand taskbar runs out on the very first one.\n *\n * `preferLeft` keeps a branch that has already turned around going the same\n * way. Without it the levels ping-pong: one flips left over its grandparent,\n * the next finds room on the right again and lands back on top of its\n * grandparent, and the chain folds into two stacks of panels.\n */\nexport function menuPanelLeft(\n ownerLeft: number,\n ownerRight: number,\n width: number,\n viewportW: number,\n gap: number,\n preferLeft = false,\n margin = 8,\n): { left: number; flipped: boolean } {\n const onRight = ownerRight + gap;\n const onLeft = ownerLeft - gap - width;\n const rightFits = onRight + width <= viewportW - margin;\n const leftFits = onLeft >= margin;\n if (preferLeft && leftFits) return { left: onLeft, flipped: true };\n if (rightFits) return { left: onRight, flipped: false };\n if (leftFits) return { left: onLeft, flipped: true };\n // Neither side fits: hug the edge the panel was heading for rather than\n // hang off the screen.\n return preferLeft\n ? { left: margin, flipped: true }\n : { left: Math.max(margin, viewportW - margin - width), flipped: false };\n}\n","import {\n createContext, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState,\n type ReactNode, type CSSProperties,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { glassStyle, GLASS_DIVIDER } from '../utils/glass';\nimport { keepsNativeMenu } from './contextMenuTarget';\nimport { registerModalEscapeInterceptor } from './escapeInterceptors';\nimport { onOverlayOpen } from './overlayEvents';\nimport { Z_LAYERS } from './zLayers';\nimport { clampMenuTop, closeMenuBelow, menuPanelLeft, openMenuLevel, type MenuAnchor } from './menuPath';\n\n/**\n * Unified popup menu component — used for all context menus, dropdowns, and flyouts.\n * Reads --menu-density CSS variable: 'tight', 'normal' (default), or 'large'.\n */\n\nexport interface PopupMenuProps {\n children: ReactNode;\n style?: CSSProperties;\n className?: string;\n onClose?: () => void;\n minWidth?: number;\n /** Render into document.body instead of in place. Required when the menu\n * is opened from INSIDE a window: the window panel is a transformed /\n * backdrop-filtered `overflow-hidden` container, which both re-anchors\n * `position: fixed` descendants to itself and clips them — a menu\n * positioned at viewport coordinates ends up offset or invisible.\n * Portaling restores true viewport positioning. */\n portal?: boolean;\n}\n\nfunction getDensity(): 'tight' | 'normal' | 'large' {\n return (getComputedStyle(document.documentElement).getPropertyValue('--menu-density')?.trim() as any) || 'normal';\n}\n\n/** Grace period before a submenu closes, so the pointer can cut the corner\n * across sibling rows on its way into the panel. The Start menu's value. */\nconst SUBMENU_CLOSE_DELAY = 200;\n/** How long the pointer rests on a submenu row before it opens. Short enough\n * to feel immediate, long enough that sweeping down a menu past the row does\n * not flash its panel open. */\nconst SUBMENU_OPEN_DELAY = 120;\n/** Gap between a submenu and the menu it opened from. */\nconst SUBMENU_GAP = 4;\n\n/**\n * What every submenu under one `PopupMenu` shares.\n *\n * The open submenus are ONE path for the whole tree — the same state machine\n * the Start menu runs (`menuPath.ts`): `path[d]` is the submenu open from a row\n * in panel `d`, and there is one close timer. That is what makes sibling\n * submenus exclusive, and it is what stops a stale timer from a row the\n * pointer merely passed over from closing a submenu that has since opened —\n * the bug the Start menu had while it ran a timer per level.\n */\ninterface MenuTree {\n /** Marks every panel of this tree, so a click inside a portalled submenu is\n * not \"outside\" the menu. */\n id: string;\n /** 0 for rows in the root menu, 1 inside its submenu, and so on. */\n depth: number;\n path: MenuAnchor[];\n open: (depth: number, anchor: MenuAnchor) => void;\n /** Close the submenus under panel `depth`, after the grace period. */\n scheduleClose: (depth: number) => void;\n /** Close the submenus under panel `depth` now. */\n closeBelow: (depth: number) => void;\n cancelClose: () => void;\n /** Close every panel — an item inside a submenu was chosen. */\n closeTree: () => void;\n /** The root panel, for measuring what it is layered at. */\n root: React.RefObject<HTMLDivElement | null>;\n}\n\nconst MenuTreeContext = createContext<MenuTree | null>(null);\n\n/** Container for a popup menu — auto-clamps to stay within viewport */\nexport function PopupMenu({ children, style, className = '', onClose, minWidth = 180, portal = false }: PopupMenuProps) {\n const ref = useRef<HTMLDivElement>(null);\n const treeId = useId();\n const [path, setPath] = useState<MenuAnchor[]>([]);\n const closeTimer = useRef<ReturnType<typeof setTimeout>>();\n useEffect(() => () => clearTimeout(closeTimer.current), []);\n\n const tree = useMemo<MenuTree>(() => {\n const cancelClose = () => clearTimeout(closeTimer.current);\n return {\n id: treeId,\n depth: 0,\n path,\n open: (depth, anchor) => { cancelClose(); setPath(prev => openMenuLevel(prev, depth, anchor)); },\n scheduleClose: depth => {\n cancelClose();\n closeTimer.current = setTimeout(() => setPath(prev => closeMenuBelow(prev, depth)), SUBMENU_CLOSE_DELAY);\n },\n closeBelow: depth => { cancelClose(); setPath(prev => closeMenuBelow(prev, depth)); },\n cancelClose,\n closeTree: () => { cancelClose(); setPath([]); onClose?.(); },\n root: ref,\n };\n }, [treeId, path, onClose]);\n\n useEffect(() => {\n if (!onClose) return;\n const handleClick = (e: PointerEvent | MouseEvent) => {\n if ((e.target as HTMLElement).closest('[data-menu-toggle]')) return;\n // A submenu is portalled to <body>, so it is outside `ref` in the DOM\n // while still being part of this menu.\n if ((e.target as HTMLElement).closest?.(`[data-popup-menu-tree=\"${treeId}\"]`)) return;\n if (ref.current && !ref.current.contains(e.target as Node)) onClose();\n };\n const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };\n window.addEventListener('pointerdown', handleClick);\n window.addEventListener('keydown', handleKey);\n // An overlay opening (⌘K's palette, a Dialog) is an outside interaction\n // the pointer listener never sees; left open, the menu would sit over the\n // overlay's backdrop or behind it (see `overlayEvents.ts`).\n const offOverlay = onOverlayOpen(onClose);\n return () => {\n window.removeEventListener('pointerdown', handleClick);\n window.removeEventListener('keydown', handleKey);\n offOverlay();\n };\n }, [onClose, treeId]);\n\n // After render, clamp position to viewport boundaries\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n requestAnimationFrame(() => {\n const rect = el.getBoundingClientRect();\n const margin = 8;\n // Clamp right edge\n if (rect.right > window.innerWidth - margin) {\n const overflow = rect.right - window.innerWidth + margin;\n if (el.style.left) {\n el.style.left = `${parseFloat(el.style.left) - overflow}px`;\n } else if (!el.style.right) {\n el.style.left = `${rect.left - overflow}px`;\n }\n }\n // Clamp left edge\n if (rect.left < margin) {\n if (el.style.left) {\n el.style.left = `${margin}px`;\n } else if (el.style.right) {\n el.style.right = `${window.innerWidth - rect.width - margin}px`;\n }\n }\n // Clamp bottom edge\n if (rect.bottom > window.innerHeight - margin) {\n const overflow = rect.bottom - window.innerHeight + margin;\n if (el.style.top) {\n el.style.top = `${parseFloat(el.style.top) - overflow}px`;\n } else if (el.style.bottom) {\n // Already anchored to bottom, just clamp\n el.style.bottom = `${margin}px`;\n } else {\n el.style.top = `${rect.top - overflow}px`;\n }\n }\n // Clamp top edge\n if (rect.top < margin) {\n if (el.style.top) {\n el.style.top = `${margin}px`;\n } else if (el.style.bottom) {\n el.style.bottom = `${window.innerHeight - rect.height - margin}px`;\n }\n }\n });\n });\n\n const density = getDensity();\n const ownsZ = /(^|[\\s:])!?z-/.test(className);\n\n // A right-click on an open menu is not a request for another menu. Claiming\n // it stops the shell-wide `ShellContextMenu` (which stands down on a\n // prevented event) and the browser's from opening on top of this one. A text\n // field inside a menu still keeps the browser's, as it does everywhere else.\n const menu = (\n <div ref={ref}\n data-popup-menu-tree={treeId}\n className={`fixed rounded-2xl ${density === 'tight' ? 'py-1' : density === 'large' ? 'py-2' : 'py-1.5'} ${className}`}\n onContextMenu={e => { if (!keepsNativeMenu(e.target)) e.preventDefault(); }}\n // The menu layer is inline now, and an inline z-index beats any class —\n // so a caller that layered its menu with a `z-…` class keeps its own.\n style={{ ...(ownsZ ? {} : { zIndex: Z_LAYERS.menu }), minWidth, animation: 'popup-in 0.12s ease-out', ...glassStyle(), ...style }}>\n <MenuTreeContext.Provider value={tree}>{children}</MenuTreeContext.Provider>\n <style>{`@keyframes popup-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }`}</style>\n </div>\n );\n\n return portal ? createPortal(menu, document.body) : menu;\n}\n\n/** A clickable menu item */\nexport interface PopupMenuItemProps {\n onClick?: () => void;\n children: ReactNode;\n className?: string;\n danger?: boolean;\n disabled?: boolean;\n /**\n * The menu semantics, when this item is part of one.\n *\n * A context menu on the desktop is a list of buttons and needs none of this;\n * a dropdown attached to a trigger is a `menu` whose items are `menuitem`s\n * with one tab stop between them. Both draw the same item, so the styling\n * lives here rather than being copied into whichever one is newer.\n */\n role?: 'menuitem';\n tabIndex?: number;\n id?: string;\n onMouseEnter?: () => void;\n}\n\n/**\n * `forwardRef`, not a `ref` prop.\n *\n * Taking `ref` as an ordinary prop is React 19 only. This package's peer range\n * is `react: \">=18\"`, and React 18 strips `ref` from a function component's\n * props and warns — so on an 18 consumer the ref would silently never attach,\n * `DropdownMenu`'s `itemRefs` would all be null, and its arrow keys would move\n * `tabIndex` while DOM focus stayed put. A keyboard-dead menu with no error.\n */\n/** The row look shared by an item and a submenu's row. */\nfunction itemLook(danger: boolean | undefined, disabled: boolean | undefined, className: string, highlighted = false) {\n const density = getDensity();\n // Vertical gap between items. `normal` sits a little tighter than the raw\n // size padding; `large` adds a bit more room. Floored at the tight value so\n // the reduced `normal` never drops below `tight` at the smallest menu size.\n const itemPadY = density === 'tight' ? '0.25rem'\n : density === 'large' ? '0.6rem'\n : 'max(0.25rem, calc(var(--menu-padding-y, 0.5rem) - 0.1rem))';\n const tone = danger ? 'text-red-600 hover:bg-red-50'\n : highlighted ? 'bg-blue-50 text-blue-700'\n : 'text-gray-700 hover:bg-blue-50 hover:text-blue-700';\n return {\n className: `w-full flex items-center gap-2 text-left transition-colors rounded-lg mx-auto\n ${tone}\n ${disabled ? 'opacity-40 cursor-not-allowed' : ''}\n ${className}`,\n style: {\n width: 'calc(100% - 8px)',\n marginLeft: 4,\n marginRight: 4,\n fontSize: 'var(--menu-font-size, 14px)',\n paddingLeft: 'var(--menu-padding-x, 1rem)',\n paddingRight: 'var(--menu-padding-x, 1rem)',\n paddingTop: itemPadY,\n paddingBottom: itemPadY,\n } satisfies CSSProperties,\n };\n}\n\nexport const PopupMenuItem = forwardRef<HTMLButtonElement, PopupMenuItemProps>(function PopupMenuItem({\n onClick, children, className = '', danger, disabled,\n role, tabIndex, id, onMouseEnter,\n}, ref) {\n const tree = useContext(MenuTreeContext);\n const look = itemLook(danger, disabled, className);\n return (\n <button\n ref={ref}\n id={id}\n role={role}\n tabIndex={tabIndex}\n onClick={() => {\n onClick?.();\n // Inside a submenu, choosing an item is the end of the whole menu —\n // not just the panel it sat in. A root item keeps its old contract:\n // the caller's own onClick decides.\n if (tree && tree.depth > 0) tree.closeTree();\n }}\n onMouseEnter={() => {\n // Resting on a plain row retires any submenu open beside it, after the\n // same grace the Start menu gives.\n tree?.scheduleClose(tree.depth);\n onMouseEnter?.();\n }}\n disabled={disabled}\n className={look.className}\n style={look.style}\n >\n {children}\n </button>\n );\n});\n\nexport interface PopupSubmenuProps {\n /** The row's text. */\n label: ReactNode;\n /** Drawn before the label, as in a `PopupMenuItem`. */\n icon?: ReactNode;\n /** The submenu's contents — `PopupMenuItem`, `PopupMenuLabel`,\n * `PopupMenuDivider`, or another `PopupSubmenu`. */\n children: ReactNode;\n disabled?: boolean;\n className?: string;\n /** The submenu panel's minimum width. */\n minWidth?: number;\n /** The tallest the panel may grow before its items scroll — a long target\n * list, say `'min(60vh, 420px)'`. Never taller than the viewport less its\n * 8px gutters, whatever is passed. */\n maxHeight?: number | string;\n}\n\nconst chevron = (\n <svg aria-hidden className=\"h-3.5 w-3.5 shrink-0 ml-auto text-gray-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n </svg>\n);\n\n/** The z-index a panel must beat: the outermost stacking level `el` sits in\n * at <body>, since a portalled submenu is compared against that, not against\n * whatever the root menu is nested inside. */\nfunction layerOf(el: HTMLElement | null): number {\n let z: number = Z_LAYERS.menu;\n for (let node = el; node && node !== document.body; node = node.parentElement) {\n const value = parseInt(getComputedStyle(node).zIndex, 10);\n if (!Number.isNaN(value)) z = value;\n }\n return z;\n}\n\n/** Enabled items of a panel, in order — what the arrow keys walk. */\nfunction focusables(panel: HTMLElement | null): HTMLElement[] {\n if (!panel) return [];\n return [...panel.querySelectorAll<HTMLElement>('button:not([disabled])')]\n .filter(b => b.closest('[data-popup-submenu-panel]') === panel);\n}\n\n/**\n * A row in a `PopupMenu` that opens a nested menu.\n *\n * Opens on hover after a short rest, and at once on click, Enter, Space or\n * ArrowRight (which also move focus to its first item). ArrowLeft and Escape\n * close it and give focus back to the row. It opens to the right of the menu,\n * or to the left when there is no room, and moves up when it would run off the\n * bottom — the Start menu's placement rules, from `menuPath.ts`. Choosing an\n * item inside closes the whole menu (the root `PopupMenu`'s `onClose`).\n */\nexport function PopupSubmenu({ label, icon, children, disabled, className = '', minWidth = 180, maxHeight }: PopupSubmenuProps) {\n const tree = useContext(MenuTreeContext);\n const key = useId();\n const rowRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const openTimer = useRef<ReturnType<typeof setTimeout>>();\n /** Whether the current opening came from the keyboard — then focus moves in. */\n const focusOnOpen = useRef(false);\n const panelId = `${key}-menu`;\n useEffect(() => () => clearTimeout(openTimer.current), []);\n\n const depth = tree?.depth ?? 0;\n const anchor = tree?.path[depth];\n const isOpen = !!anchor && anchor.key === key && !disabled;\n\n const openNow = useCallback((withFocus: boolean) => {\n if (!tree || disabled || !rowRef.current) return;\n clearTimeout(openTimer.current);\n focusOnOpen.current = withFocus;\n const row = rowRef.current.getBoundingClientRect();\n const owner = (rowRef.current.closest('[data-popup-submenu-panel]')\n ?? rowRef.current.closest('[data-popup-menu-tree]')) as HTMLElement | null;\n const ownerRect = owner?.getBoundingClientRect() ?? row;\n const preferLeft = depth > 0 && (tree.path[depth - 1]?.flipped ?? false);\n const place = menuPanelLeft(ownerRect.left, ownerRect.right, minWidth, window.innerWidth, SUBMENU_GAP, preferLeft);\n tree.open(depth, { key, y: row.top, ...place });\n }, [tree, disabled, depth, key, minWidth]);\n\n const closeSelf = (restoreFocus: boolean) => {\n tree?.closeBelow(depth);\n if (restoreFocus) rowRef.current?.focus();\n };\n\n // Escape through the shell's interceptor seam: inside a window, `Modal`\n // takes Escape in the capture phase and would close the whole window.\n useEffect(() => {\n if (!isOpen) return;\n return registerModalEscapeInterceptor(e => {\n if (e.key !== 'Escape') return false;\n // Registration order cannot say which submenu is deepest: React runs a\n // parent's effects after its children's, so once both re-render the\n // outer submenu is the newest registrant and is asked first. Defer to\n // the open path instead — a deeper level open under this one takes it.\n if (tree && tree.path.length > depth + 1) return false;\n closeSelf(true);\n return true;\n });\n });\n\n // Place the panel against its real size before paint — the estimate used\n // `minWidth` and the row's top — then move focus in if a key opened it.\n useLayoutEffect(() => {\n if (!isOpen || !anchor) return;\n const place = () => {\n const panel = panelRef.current;\n if (!panel || !rowRef.current) return;\n const margin = 8;\n const owner = (rowRef.current.closest('[data-popup-submenu-panel]')\n ?? rowRef.current.closest('[data-popup-menu-tree]')) as HTMLElement | null;\n const ownerRect = owner?.getBoundingClientRect() ?? rowRef.current.getBoundingClientRect();\n const preferLeft = depth > 0 && (tree?.path[depth - 1]?.flipped ?? false);\n const width = panel.offsetWidth || minWidth;\n const spot = menuPanelLeft(ownerRect.left, ownerRect.right, width, window.innerWidth, SUBMENU_GAP, preferLeft, margin);\n const height = panel.offsetHeight;\n // Top-aligned with the row: centring the clamp on `row top + half the\n // panel` gives exactly that, and still moves the panel up at the bottom.\n const rowTop = rowRef.current.getBoundingClientRect().top;\n const top = clampMenuTop(rowTop + height / 2, height, margin, window.innerHeight - margin);\n panel.style.left = `${spot.left}px`;\n panel.style.top = `${top}px`;\n panel.dataset.flipped = String(spot.flipped);\n };\n place();\n // Again after the root menu's own viewport clamp, which runs in a frame\n // AFTER this effect: on a re-render it can still move the root a few\n // pixels, and the submenu has to follow the menu it hangs off.\n let second = 0;\n const first = requestAnimationFrame(() => { second = requestAnimationFrame(place); });\n return () => { cancelAnimationFrame(first); cancelAnimationFrame(second); };\n });\n\n useEffect(() => {\n if (!isOpen || !focusOnOpen.current) return;\n focusOnOpen.current = false;\n focusables(panelRef.current)[0]?.focus();\n }, [isOpen]);\n\n const childTree = useMemo<MenuTree | null>(() => tree && { ...tree, depth: depth + 1 }, [tree, depth]);\n\n if (!tree) throw new Error('PopupSubmenu must be rendered inside a PopupMenu');\n\n const onRowKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n e.stopPropagation();\n openNow(true);\n }\n };\n\n const onPanelKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n // React bubbles through portals, so a key pressed in a deeper submenu\n // reaches this handler too. That panel handled it already.\n if ((e.target as HTMLElement).closest('[data-popup-submenu-panel]') !== e.currentTarget) return;\n const items = focusables(panelRef.current);\n const at = items.indexOf(document.activeElement as HTMLElement);\n const move = (to: number) => { e.preventDefault(); e.stopPropagation(); items[(to + items.length) % items.length]?.focus(); };\n if (e.key === 'ArrowDown') move(at + 1);\n else if (e.key === 'ArrowUp') move(at < 0 ? items.length - 1 : at - 1);\n else if (e.key === 'Home') move(0);\n else if (e.key === 'End') move(items.length - 1);\n else if (e.key === 'ArrowLeft') { e.preventDefault(); e.stopPropagation(); closeSelf(true); }\n };\n\n const look = itemLook(false, disabled, className, isOpen);\n const density = getDensity();\n\n return (\n <>\n <button\n ref={rowRef}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? panelId : undefined}\n disabled={disabled}\n data-popup-submenu-row\n className={look.className}\n style={look.style}\n onClick={e => {\n // `detail` is 0 for a click the keyboard made (Enter, Space).\n const byKey = e.detail === 0;\n if (!isOpen) openNow(byKey);\n else if (byKey) focusables(panelRef.current)[0]?.focus();\n }}\n onKeyDown={onRowKeyDown}\n onMouseEnter={() => {\n if (disabled) return;\n tree.cancelClose();\n if (isOpen) { tree.closeBelow(depth + 1); return; }\n clearTimeout(openTimer.current);\n openTimer.current = setTimeout(() => openNow(false), SUBMENU_OPEN_DELAY);\n }}\n onMouseLeave={() => {\n clearTimeout(openTimer.current);\n tree.scheduleClose(depth);\n }}\n >\n {icon}\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {chevron}\n </button>\n {isOpen && createPortal(\n <div\n ref={panelRef}\n id={panelId}\n role=\"menu\"\n data-popup-menu-tree={tree.id}\n data-popup-submenu-panel\n className={`fixed rounded-2xl overflow-x-hidden overflow-y-auto overscroll-contain ${density === 'tight' ? 'py-1' : density === 'large' ? 'py-2' : 'py-1.5'}`}\n style={{\n left: anchor!.left, top: anchor!.y, minWidth,\n // The viewport cap always applies, so a long list scrolls rather\n // than running off the screen even when no maxHeight is passed.\n maxHeight: maxHeight === undefined\n ? 'calc(100vh - 16px)'\n : `min(${typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight}, calc(100vh - 16px))`,\n zIndex: layerOf(tree.root.current) + depth + 1,\n animation: `${anchor!.flipped ? 'popup-submenu-in-left' : 'popup-submenu-in'} 0.1s ease-out`,\n ...glassStyle(),\n }}\n onKeyDown={onPanelKeyDown}\n onMouseEnter={() => { tree.cancelClose(); clearTimeout(openTimer.current); }}\n onMouseLeave={() => tree.scheduleClose(depth + 1)}\n onContextMenu={e => { if (!keepsNativeMenu(e.target)) e.preventDefault(); }}\n >\n <MenuTreeContext.Provider value={childTree}>{children}</MenuTreeContext.Provider>\n <style>{`@keyframes popup-submenu-in { from { opacity: 0; transform: translateX(-4px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes popup-submenu-in-left { from { opacity: 0; transform: translateX(4px); } to { opacity: 1; transform: translateX(0); } }`}</style>\n </div>,\n document.body,\n )}\n </>\n );\n}\n\n/** A divider line between menu items */\nexport function PopupMenuDivider() {\n const density = getDensity();\n return <div className={`border-t ${GLASS_DIVIDER} ${density === 'tight' ? 'my-0.5' : density === 'large' ? 'my-1.5' : 'my-1'} mx-3`} />;\n}\n\n/** A section header label */\nexport function PopupMenuLabel({ children }: { children: ReactNode }) {\n const density = getDensity();\n const labelPadY = density === 'tight' ? '0.125rem' : density === 'large' ? '0.375rem' : '0.25rem';\n return (\n <div\n className=\"text-[10px] font-medium text-gray-400 uppercase tracking-wider\"\n style={{\n paddingLeft: 'var(--menu-padding-x, 1rem)',\n paddingRight: 'var(--menu-padding-x, 1rem)',\n paddingTop: labelPadY,\n paddingBottom: labelPadY,\n }}\n >\n {children}\n </div>\n );\n}\n\n/** An icon helper */\nexport function MenuIcon({ d, className = 'h-4 w-4 text-gray-400' }: { d: string; className?: string }) {\n return (\n <svg className={className} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d={d} />\n </svg>\n );\n}\n"]}
|