Mixins / foldkit-mixins-ui

MenubarSlots

const · packages/mixins-ui/src/menubar.ts:31

const MenubarSlots: Slots.Contract<{
  readonly bar: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly [Event.EventToken<'keydown'>],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly menu: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly [Event.EventToken<'hover'>],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
}>

A menu bar, shadcn's and the APG's: a row of @foldkit/ui Menus, so each menu's keys, typeahead, rows and dismissal stay the Menu's, and the bar adds what a row of them needs. One trigger is the bar's tab stop, and ArrowLeft and ArrowRight (Home and End while all are shut) move it; with a menu open they shut it and open the next, its first row active. While one is open, pointing at another trigger opens that one, and opening any menu shuts the rest. The menus' Models are this module's Model, which the application keeps and folds with update, as it folds a Menu's.

The bar's keys and hover listen outside each menu's submodel (a handler inside it would speak the Menu's Messages): keydown on the bar, which the triggers and rows bubble to, and mouseenter on each menu. The triggers stand above an open menu's backdrop (z-index: 1), which holds only while nothing between the bar and the page makes a stacking context.