Components

Menu

Actions behind a button, in groups, moved through by the keys and typed to.

size
scheme

Nothing chosen yet

forSlots(MenuSlots)(Recipes.Menu({}))

Usage

The function that drew the preview, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.

export const MenuStyle = forSlots(MenuSlots)(Recipes.Menu({}))

export const Action = Schema.Literals(['Rename', 'Duplicate', 'Move', 'Delete'])
export type Action = typeof Action.Type
// Annotated: the inferred type names a foldkit internal module.
export const ActionMenu: ReturnType<typeof MenuView.create<Action>> = MenuView.create<Action>()

/** The open menu is the component's; the action chosen is the Model's. */
export interface MenuState {
  readonly menu: UiMenu.Model
  readonly action: Option.Option<Action>
}

export const menu = <Message>(
  style: NamedStyle<typeof MenuSlots>,
  state: MenuState,
  toMessage: (message: UiMenu.Message) => Message,
  h: HtmlBuilder<Message>,
): Html =>
  h.div(
    [h.Style({ display: 'grid', gap: '0.75rem', justifyItems: 'start' })],
    [
      h.submodel({
        slotId: state.menu.id,
        model: state.menu,
        view: ActionMenu.view,
        viewInputs: {
          anchor: { placement: 'bottom-start', gap: 4, padding: 8, portal: false },
          items: Action.literals,
          itemToConfig: (action: Action) => ({ content: h.span([], [action]) }),
          isItemDisabled: (action: Action) => action === 'Move',
          buttonContent: h.span([], ['Page actions']),
          toView: Menu.toView([style.mixin, ...Menu.fluid], { h }),
        },
        toParentMessage: toMessage,
      }),
      h.p(
        [],
        [
          Option.match(state.action, {
            onNone: () => 'Nothing chosen yet',
            onSome: a => `Chose ${a}`,
          }),
        ],
      ),
    ],
  )

The recipe ↗This code ↗