feat(web): adopt shadcn context-menu for mascot + desktop right-click menus
Problem: the mascot's right-click menu was non-interactive — RadialMenu's root div rendered inside MascotLayer's pointer-events-none root (and the new DockedLayer wrapper compounded it) without re-enabling pointer-events, so clicks passed straight through. The desktop right-click menu was a hand-rolled positioned div, inconsistent with the rest of the UI. Change: both menus now use the shadcn-svelte context-menu primitive (bits-ui, portaled to <body>). - Mascot: MascotMenu.svelte renders the action tree recursively — children become ContextMenu.Sub (native hover sub-menu navigation, replacing the manual breadcrumb stack), leaves become ContextMenu.Item with onSelect. MascotLayer wraps <Mascot> in a ContextMenu.Trigger; visibility predicates read reactively off ctx.model so items appear/disappear live. Removed the manual menuPos/openMenu/closeMenu machinery. RadialMenu.svelte deleted. - Desktop: the surface's bare-desktop hit area is now a ContextMenu.Trigger layer (absolute inset-0, pointer-events-auto) placed before the icons/windows in the DOM. The DOM-structure gate (icons/windows are pointer-events-auto siblings that paint on top and intercept their own right-clicks; bare desktop falls through to the trigger) replaces the old fragile e.currentTarget === e.target check. Left-click blur moved onto the trigger; Undo/Redo disabled state snapshotted via onOpenChange (canUndo/canRedo are wmkit methods). Risk: the blocker that made the mascot menu non-interactive in the first place — Mascot.svelte's handleContextMenu called e.stopPropagation(), which would have prevented a ContextMenu.Trigger wrapper from ever seeing the right-click. Removed that handler; bits-ui now owns right-click on the mascot, left-click drag/pet passes through. The context-menu content portals to <body>, escaping the pointer-events-none mascot and docked layers entirely — the structural fix, not just a component swap. Verification: vitest 38/38; svelte-check + tsc clean for changed files; eslint clean (the shadcn-generated ui/context-menu/* files carry the same baseline custom_element_props_identifier warnings as the rest of the ui/ folder, not from this change); vite build green; runtime confirmed — right-click mascot opens the action tree with hover sub-menus, right-click bare desktop opens Cascade/Tile/Show/Reset/ Undo/Redo, right-click on an icon or window does not.
This commit is contained in:
52
web/src/lib/components/ui/context-menu/index.ts
Normal file
52
web/src/lib/components/ui/context-menu/index.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import Root from "./context-menu.svelte";
|
||||
import Sub from "./context-menu-sub.svelte";
|
||||
import Portal from "./context-menu-portal.svelte";
|
||||
import Trigger from "./context-menu-trigger.svelte";
|
||||
import Group from "./context-menu-group.svelte";
|
||||
import RadioGroup from "./context-menu-radio-group.svelte";
|
||||
import Item from "./context-menu-item.svelte";
|
||||
import GroupHeading from "./context-menu-group-heading.svelte";
|
||||
import Content from "./context-menu-content.svelte";
|
||||
import Shortcut from "./context-menu-shortcut.svelte";
|
||||
import RadioItem from "./context-menu-radio-item.svelte";
|
||||
import Separator from "./context-menu-separator.svelte";
|
||||
import SubContent from "./context-menu-sub-content.svelte";
|
||||
import SubTrigger from "./context-menu-sub-trigger.svelte";
|
||||
import CheckboxItem from "./context-menu-checkbox-item.svelte";
|
||||
import Label from "./context-menu-label.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Sub,
|
||||
Portal,
|
||||
Item,
|
||||
GroupHeading,
|
||||
Label,
|
||||
Group,
|
||||
Trigger,
|
||||
Content,
|
||||
Shortcut,
|
||||
Separator,
|
||||
RadioItem,
|
||||
SubContent,
|
||||
SubTrigger,
|
||||
RadioGroup,
|
||||
CheckboxItem,
|
||||
//
|
||||
Root as ContextMenu,
|
||||
Sub as ContextMenuSub,
|
||||
Portal as ContextMenuPortal,
|
||||
Item as ContextMenuItem,
|
||||
GroupHeading as ContextMenuGroupHeading,
|
||||
Group as ContextMenuGroup,
|
||||
Content as ContextMenuContent,
|
||||
Trigger as ContextMenuTrigger,
|
||||
Shortcut as ContextMenuShortcut,
|
||||
RadioItem as ContextMenuRadioItem,
|
||||
Separator as ContextMenuSeparator,
|
||||
RadioGroup as ContextMenuRadioGroup,
|
||||
SubContent as ContextMenuSubContent,
|
||||
SubTrigger as ContextMenuSubTrigger,
|
||||
CheckboxItem as ContextMenuCheckboxItem,
|
||||
Label as ContextMenuLabel,
|
||||
};
|
||||
Reference in New Issue
Block a user