Code Study: GitHub Desktop / models / app-menu.ts

The file defines data models for Menu, MenuItem, and AppMenu that ecapsulates everything.

Menu vs MenuItem

Here is a list of different types of menu item:

export interface IMenuItem extends IBaseMenuItem {
  readonly type: 'menuItem'
  readonly accelerator: string | null
  readonly accessKey: string | null
}
export interface ISubmenuItem extends IBaseMenuItem {
  readonly type: 'submenuItem'
  readonly menu: IMenu
  readonly accessKey: string | null
}
export interface ICheckboxMenuItem extends IBaseMenuItem {
  readonly type: 'checkbox'
  readonly accelerator: string | null
  readonly accessKey: string | null
  readonly checked: boolean
}
export interface IRadioMenuItem extends IBaseMenuItem {
  readonly type: 'radio'
  readonly accelerator: string | null
  readonly accessKey: string | null
  readonly checked: boolean
}
export interface ISeparatorMenuItem {
  readonly id: string
  readonly type: 'separator'
  readonly visible: boolean
}

Besides these individual menu item types, we also have some type unions.

export type MenuItem =
  | IMenuItem
  | ISubmenuItem
  | ISeparatorMenuItem
  | ICheckboxMenuItem
  | IRadioMenuItem
export type ExecutableMenuItem =
  | IMenuItem
  | ICheckboxMenuItem
  | IRadioMenuItem

IMenu is an interface describing a menu. It holds collection of menu items and an indication of which item (if any)

export interface IMenu {
  /**
   * The id of this menu. For the root menu this will be undefined. For all
   * other menus it will be the same as the id of the submenu item which
   * owns this menu.
   *
   * +---------------------------+
   * | Root menu (id: undefined) |
   * +---------------------------+  +---------------------------------+
   * |  File menuitem (id File)  +--> File menu (id: File)            |
   * +---------------------------+  +---------------------------------+
   * |  Edit menuitem (id Edit)  |  |  Open menuitem (id File.Open)   |
   * +---------------------------+  +---------------------------------+
   *                                |  Close menuitem (id File.Close) |
   *                                +---------------------------------+
   */
  readonly id?: string

  /** Type identifier, used for type narrowing */
  readonly type: 'menu'

  /** A collection of zero or more menu items */
  readonly items: ReadonlyArray<MenuItem>

  /** The selected item in the menu or undefined if no item is selected */
  readonly selectedItem?: MenuItem
}

AppMenu

AppMenu is an immutable, transformable object which represents an application menu and its current state (which menus are open, which items are selected). The primary use case for this is for rendering a custom application menu on non-macOS systems. As such some interactions are explicitly made to conform to Windows menu interactions. This includes things like selecting the entire path up until the last selected item. This is necessary since, on Windows, the parent menu item of a menu might not be selected even though the submenu is. This is in order to allow for some delay when moving the cursor from one menu pane to another.

In general, however, this object is not platform specific and much of the interactions are defined by the component using it.

Private Fields

Public Methods

Helper functions

This function converts an Electron MenuItem object into one of the MenuItem data models.

This function converts an Electron Menu object into a Menu data model.

tags: GitHub Desktop - Electron