NestedMenu.init
function · packages/mixins-ui/src/nestedMenu.ts:93
function init(id: string, rows: ReadonlyArray<NestedRow>): ModelA shut menu, and a shut submenu for each row with items.
Mixins / foldkit-mixins-ui
namespace · packages/mixins-ui/src/nestedMenu.ts:1
export * as NestedMenu from './nestedMenu.js'NestedMenu.initfunction · packages/mixins-ui/src/nestedMenu.ts:93
function init(id: string, rows: ReadonlyArray<NestedRow>): ModelA shut menu, and a shut submenu for each row with items.
NestedMenu.Messageconst · packages/mixins-ui/src/nestedMenu.ts:75
const Message: MessageUnion<{ readonly GotMenu: { readonly message: MessageUnion<{ readonly Opened: { maybeActiveItemIndex: Schema.Option<Schema.Number>; }; readonly Closed: {}; readonly BlurredItems: {}; readonly ActivatedItem: { index: Schema.Number; activationTrigger: Schema.Literals<readonly ["Pointer", "Keyboard"]>; }; readonly DeactivatedItem: {}; readonly SelectedItem: { index: Schema.Number; item: Schema.String; }; readonly RequestedItemClick: { index: Schema.Number; }; readonly Searched: { key: Schema.String; maybeTargetIndex: Schema.Option<Schema.Number>; }; readonly CompletedDelayClearSearch: { version: Schema.Number; }; readonly MovedPointerOverItem: { index: Schema.Number; screenX: Schema.Number; screenY: Schema.Number; }; readonly CompletedFocusItems: {}; readonly CompletedFocusButton: {}; readonly CompletedLockScroll: {}; readonly CompletedUnlockScroll: {}; readonly CompletedInertOthers: {}; readonly CompletedRestoreInert: {}; readonly CompletedScrollIntoView: {}; readonly CompletedClickItem: {}; readonly IgnoredMouseClick: {}; readonly SuppressedSpaceScroll: {}; readonly CompletedAnchorMenu: {}; readonly CompletedPortalMenuBackdrop: {}; readonly GotAnimationMessage: { message: import("foldkit/message").MessageUnion<{ readonly Showed: {}; readonly Hid: {}; readonly CompletedWaitForPaint: { generation: Schema.Number; }; readonly EndedAnimation: { generation: Schema.Number; }; }>; }; readonly PressedPointerOnButton: { pointerType: Schema.String; button: Schema.Number; screenX: …;NestedMenu.Modelconst · packages/mixins-ui/src/nestedMenu.ts:63
const Model: Schema.Struct<{ readonly menu: Schema.Struct<{ readonly id: Schema.String; readonly isOpen: Schema.Boolean; readonly isAnimated: Schema.Boolean; readonly isModal: Schema.Boolean; readonly animation: Schema.Struct<{ readonly id: Schema.String; readonly isShowing: Schema.Boolean; readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>; readonly transitionGeneration: Schema.Number; }>; readonly maybeActiveItemIndex: Schema.Option<Schema.Number>; readonly activationTrigger: Schema.Literals<readonly ["Pointer", "Keyboard"]>; readonly searchQuery: Schema.String; readonly searchVersion: Schema.Number; readonly maybeLastPointerPosition: Schema.Option<Schema.Struct<{ readonly screenX: Schema.Number; readonly screenY: Schema.Number; }>>; readonly maybeLastButtonPointerType: Schema.Option<Schema.String>; readonly maybePointerOrigin: Schema.Option<Schema.Struct<{ readonly screenX: Schema.Number; readonly screenY: Schema.Number; readonly timeStamp: Schema.Number; }>>; }>; readonly submenus: Schema.$Array<Schema.Struct<{ readonly row: Schema.Number; readonly label: Schema.String; readonly menu: Schema.Struct<{ readonly id: Schema.String; readonly isOpen: Schema.Boolean; readonly isAnimated: Schema.Boolean; readonly isModal: Schema.Boolean; readonly animation: Schema.Struct<{ readonly id: Schema.String; readonly isShowing: Schema.Boolean; readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnima …;NestedMenu.NestedMenuSlotsconst · 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.
NestedMenu.NestedMenuViewinterface · packages/mixins-ui/src/nestedMenu.ts:361
interface NestedMenuView<ParentMessage> {
readonly model: Model
readonly rows: ReadonlyArray<NestedRow>
readonly buttonContent: Html
readonly isRowDisabled?: ((label: string) => boolean) | undefined
readonly onMessage: (message: Message) => NoInfer<ParentMessage>
readonly style?: NamedStyle<typeof NestedMenuSlots> | undefined
readonly menuMixins: MixinList<ParentMessage>
readonly submenuMixins: MixinList<ParentMessage>
}NestedMenu.NestedRowinterface · packages/mixins-ui/src/nestedMenu.ts:49
interface NestedRow {
readonly label: string
readonly items?: ReadonlyArray<string> | undefined
readonly isItemDisabled?: ((item: string) => boolean) | undefined
}One row of the menu; a row with items opens a submenu of them.
NestedMenu.OutMessageconst · packages/mixins-ui/src/nestedMenu.ts:86
const OutMessage: MessageUnion<{
readonly Selected: {
readonly value: Schema.String
readonly submenu: Schema.Option<Schema.String>
}
}>NestedMenu.updatefunction · packages/mixins-ui/src/nestedMenu.ts:300
function update(model: Model, message: Message): ReturnThe menu after message; the same Model when nothing changes.
NestedMenu.viewfunction · packages/mixins-ui/src/nestedMenu.ts:391
function view<ParentMessage>(
options: NestedMenuView<ParentMessage>,
h: HtmlBuilder<ParentMessage>,
): Html