Problem
@netscript/fresh-ui already has the right low-level runtime (usePopover and useDismissableLayer), but it does not expose a reusable action-menu composition for application rows/cards. Consumers fall back to native
Details
menus and document-level event listeners. In eis-chat this caused every row menu to remain open after outside clicks, Escape, or item activation until a global workaround was added.
This is distinct from the DataGrid selection API in #947: DataGrid should consume the menu, while ActionMenu should also work on cards, list items, and arbitrary triggers.
Requested surface
- typed compound API such as ActionMenu.Root, Trigger, Content, Item, Separator`n- controlled and uncontrolled open state
- built on the existing popover/dismissable-layer runtime, not new document-global listeners
- close on outside pointer interaction, Escape, and item selection
- restore focus to the trigger after dismissal
- ArrowUp/ArrowDown/Home/End navigation and correct menu/menuitem semantics
- collision-aware placement and portal behavior consistent with Popover
- event isolation suitable for clickable DataGrid/list rows (menu actions must not navigate the row)
- destructive, disabled, and loading item states
Acceptance criteria
A consumer can place the menu inside a selectable/linkable row without invalid nested interactive markup, without custom click-away code, and with keyboard/focus behavior covered by tests.
Dogfood evidence
eis-chat PR #152 currently carries DismissableOverlays.tsx as a scoped fallback. Once this primitive ships, that global compatibility layer and the hand-rolled
action menus should be removed.
Related: #947, #509
Problem
@netscript/fresh-ui already has the right low-level runtime (usePopover and useDismissableLayer), but it does not expose a reusable action-menu composition for application rows/cards. Consumers fall back to native
Details
menus and document-level event listeners. In eis-chat this caused every row menu to remain open after outside clicks, Escape, or item activation until a global workaround was added.This is distinct from the DataGrid selection API in #947: DataGrid should consume the menu, while ActionMenu should also work on cards, list items, and arbitrary triggers.
Requested surface
Acceptance criteria
A consumer can place the menu inside a selectable/linkable row without invalid nested interactive markup, without custom click-away code, and with keyboard/focus behavior covered by tests.
Dogfood evidence
eis-chat PR #152 currently carries DismissableOverlays.tsx as a scoped fallback. Once this primitive ships, that global compatibility layer and the hand-rolled
Related: #947, #509