Rask
Rask
v0.23.1-alpha.0.440

Components

Context menu

The menu a dropdown opens, opened by a right-click instead: the first child of Ui.Context is the area, the second the Ui.Menu, with the same rows and the same keyboard.

Drawn and behaving as Flux UI's context menu does, measured against its live docs.

Context menu

Right-click the area. The runtime opens the menu at the pointer at once, on either host, and the ContextMenu key or Shift+F10 opens it at the focused element. iOS never fires the event, so nothing in it should be the only way to do something.

ContextExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class ContextExample : Component
{
    private string _sort = "name";
    private string _last = "nothing yet";

    protected override Component? Render() =>
        Div.Class("space-y-4")[
            Ui.Context[
                // Focusable, so the ContextMenu key and Shift+F10 open it too.
                Div.TabIndex(0)
                    .Class("inline-block rounded-lg border-2 border-dashed border-zinc-300 px-16 py-6 text-sm "
                           + "text-zinc-500 dark:border-zinc-600 dark:text-zinc-400")["Right click"],
                Ui.Menu[
                    Ui.MenuItem.Icon(Ui.IconName.Plus).OnClick(() => { _last = "new post"; })["New post"],
                    Ui.MenuSeparator.Key("s1"),
                    Ui.MenuSubmenu.Heading("Sort by")[
                        Ui.MenuRadioGroup.Value(_sort).OnChange(sort => { _sort = sort; _last = "sorted by " + sort; })[
                            Ui.MenuRadio.Value("name")["Name"],
                            Ui.MenuRadio.Value("date")["Date"],
                            Ui.MenuRadio.Value("popularity")["Popularity"]
                        ]
                    ],
                    Ui.MenuSeparator.Key("s2"),
                    Ui.MenuItem.Danger.Icon(Ui.IconName.Trash).OnClick(() => { _last = "deleted"; })["Delete"]
                ]
            ],
            Ui.Text[$"Last action: {_last}."]
        ];
}
Live result
Right click

Last action: nothing yet.

Behaviour

Opening

The first child of Ui.Context is the area that is right-clicked, and the second is the Ui.Menu, the same one a Ui.Dropdown opens, so the rows and the keyboard are identical: only the opening differs.

The runtime opens it: an element carrying data-rask-contextmenu="<popover id>" shows that popover at the pointer in place of the browser's menu, straight away and on either host. A round trip first would be a lag felt on every right-click.

Nothing in a context menu should be the only way to do something: iOS Safari never fires the event, so put the same actions somewhere visible too.

Where it lands

Where Flux's does: below the pointer, with the menu's end edge on it. Near an edge of the viewport it opens over the pointer, or with its start edge on it, and is slid back to stay 5px inside.

Position (BottomEnd, BottomCenter, BottomStart, TopEnd, TopCenter, TopStart), Gap and Offset((x, y)) move it. Target("id") opens a Ui.Menu.Id("id") written somewhere else; Detail lands on the menu as data-detail; Disabled leaves the browser's own menu alone.

While it is open the page behind neither scrolls nor takes the pointer (data-rask-lock), as for a dropdown's menu.

Keyboard

The ContextMenu key and Shift+F10 open it at the focused element, which is why the area is focusable. Unlike Flux's, the menu takes focus as it opens, so the arrow keys work at once; from there every key is the dropdown's.

Reference

Ui.Context

flux:context

Opens its second child, a Ui.Menu, at the pointer when its first child is right-clicked.

Step
Takes
What it does
.Position(…)
Ui.ContextPosition
BottomEnd
BottomCenter
BottomStart
TopEnd
TopCenter
TopStart

Each is a step of its own too, unless an HTML tag has its name.

Where the menu opens against the pointer. Below it, its end edge on it, when unset.
.Gap(…)intThe distance between the pointer and the menu, in pixels.
.Offset(…)(int X, int Y)Shifts the menu from where it would open, in pixels.
.Target(…)stringThe id of a Ui.Menu written somewhere else, for one that cannot sit inside.
.Detail(…)stringA value for the menu's data-detail, to tell which area opened it.
.Disabled()boolLeaves a right-click to the browser's own menu.
.Open()boolHands the open state to the page. Unset, the reader opens and closes it.
.OnToggle(…)a handler given the state it is now in: open => …Runs when the reader opens or closes it.