Mixins / foldkit-mixins-ui

NestedMenuSlots

const · packages/mixins-ui/src/nestedMenu.ts:40

const NestedMenuSlots: Slots.Contract<{
  readonly sub: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly label: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly chevron: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
}>

A menu whose rows may open submenus, shadcn's DropdownMenuSub and the APG's: @foldkit/ui Menus, one for the menu and one per submenu, so each keeps its own keys, typeahead and rows. A submenu's row is a menuitem with aria-haspopup="menu" and aria-expanded. ArrowRight, Enter or Space on it opens the submenu with its first row active, and ArrowLeft or Escape closes it back to that row; resting the pointer on it opens it after a short delay, and resting on another row closes it. Choosing a submenu's row closes the whole menu. The Menus' Models are this module's Model, which the application keeps and folds with update, as it folds a Menu's.

Each submenu is drawn inside its row, so the submenu's own anchor places it beside the row: its button is a mark the size of the row that nothing sees, focuses or presses. Being inside the row, every key, click and release in a submenu also bubbles to the menu's panel, which answers in the Menu's Messages. update reads those against its own Model: while a submenu is open, focus is in it, so the menu's key Messages and its blur are the submenu's and are dropped, and the menu's Closed is the submenu's Escape. The submenu's own Closed is dropped for that reason, and it draws no click-away: the menu's serves both, closing everything on pointerdown. The keys the Menu does not answer (ArrowRight, ArrowLeft, and Tab while a submenu is open) are heard on the menu's panel, outside the submenus.

One level deep. Pass Menu.fluid to the submenus only: the menu's rows hold its submenus' rows, which its highlight would chase too.