feat(e10): open the app's menu with a right-click, starting with playlist rows
S2's headline was never a new Menu: `ActionMenu` already sits on `AnchoredPopover` (arrows, typeahead, Escape, anchor-flip). What was missing is an INPUT PATH into it, so this adds `useContextMenu` + `<ContextMenu>` over the same `ActionMenuItem[]` and the same `MenuItemList` — a row cannot grow a right-click menu that looks or behaves unlike its own ⋯ menu. Three ways in: right-click anywhere on the row, long-press on touch/pen, and Shift+F10 / the Menu key. The LEFT button is untouched and keeps the row's own action. One popover per list, anchored to a virtual element at the pointer (native behaviour, and a table of 200 rows would otherwise mount 200 floating contexts to keep 199 shut). Platform bits it needed: `hoverAlso` on AnchoredPopover (a submenu falls open under a mouse and is tapped by a finger — mouse-only, so a tap's synthetic mouseenter can't race the click toggle) and `elementRef` on PopoverItem (the submenu anchors to the very menuitem that opens it, where aria-haspopup/expanded belong). `ActionMenuItem` becomes a discriminated union — a row either fires or opens a submenu — plus `danger` and `separatorBefore`. First consumers, both in Playlists: - item rows: play · move to another list (a submenu of every other playlist, one gesture) · to top / up / down / bottom · remove. Reordering goes through the same undoable store as the drag handle and is disabled under a view for the same reason, with the same explanation rather than silence. - rail rows: rename (in the row that was right-clicked, keeping its cover so the rail doesn't jump) · delete. Both now run through `usePlaylistActions`, which also takes over the detail header's pencil and trash — the delete dialog's YouTube branch and the "what gets selected next" rule exist once, not twice. - the rail gains a "recently changed" sort key off the new `updated_at`. NOT the default: a rail that reshuffles itself while you look at it costs more than it saves.
This commit is contained in:
@@ -559,6 +559,22 @@ body {
|
||||
min-height: 2.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== E10 S2 · rows that answer a right-click / long-press (useContextMenu) =====
|
||||
The long-press path competes with two browser behaviours that fire at the same gesture:
|
||||
iOS Safari's own callout (Copy / Share over a link or image) and the text-selection handles.
|
||||
Both would appear ON TOP of our menu, so the attribute the hook stamps on the row turns them
|
||||
off. Deliberately NOT `user-select: none` on a precise pointer — selecting a video title with
|
||||
the mouse is legitimate, and only the touch path has the conflict. */
|
||||
[data-context-menu-target] {
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
@media (pointer: coarse) {
|
||||
[data-context-menu-target] {
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.glass-hover:hover {
|
||||
border-color: color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
|
||||
Reference in New Issue
Block a user