TermUI.Widgets.ContextMenu.Factory (TermUI v1.0.0)

View Source

Factory for creating context menus with automatic mode selection.

This module provides a unified way to create context menus that automatically selects between positioned (mouse) and inline (keyboard) modes based on terminal capabilities and provided options.

Usage

# Auto-detect: uses positioned if position provided, inline otherwise
{:ok, {module, props}} = Factory.create(
  items: [
    ContextMenu.action(:copy, "Copy"),
    ContextMenu.action(:paste, "Paste")
  ],
  position: {10, 5},  # Optional - triggers positioned mode
  on_select: fn id -> handle_action(id) end
)

# Force inline mode
{:ok, {module, props}} = Factory.create(
  items: items,
  mode: :inline,
  on_select: on_select
)

# Force positioned mode (requires position)
{:ok, {module, props}} = Factory.create(
  items: items,
  mode: :positioned,
  position: {x, y},
  on_select: on_select
)

Mode Selection

The factory selects a menu mode based on:

  1. Explicit mode - If :mode option is provided:

    • :inline - Always use ContextMenu.Inline
    • :positioned - Always use ContextMenu (requires :position)
    • :auto - Auto-detect based on position and capabilities (default)
  2. Auto-detection (:mode == :auto or not specified):

    • If :position is provided → use positioned ContextMenu
    • If no position and mouse not supported → use ContextMenu.Inline
    • If no position but mouse supported → returns error (caller should provide position)

Return Value

Returns {:ok, {module, props}} where:

Or {:error, reason} if the configuration is invalid.

Summary

Functions

Creates a context menu with automatic mode selection.

Creates a context menu, raising on error.

Returns whether the terminal supports mouse tracking.

Types

mode()

@type mode() :: :auto | :positioned | :inline

option()

@type option() ::
  {:items, [map()]}
  | {:position, {non_neg_integer(), non_neg_integer()}}
  | {:mode, mode()}
  | {:on_select, (term() -> any())}
  | {:on_close, (-> any())}
  | {:orientation, :horizontal | :vertical}
  | {:item_style, term()}
  | {:selected_style, term()}
  | {:disabled_style, term()}
  | {:number_style, term()}

Functions

create(opts)

@spec create(keyword()) :: {:ok, {module(), map()}} | {:error, atom()}

Creates a context menu with automatic mode selection.

Options

  • :items - List of menu items (required). Use ContextMenu.action/3 and ContextMenu.separator/0 to create items.
  • :position - {x, y} tuple for positioned mode. If provided and mode is :auto, positioned mode will be used.
  • :mode - Explicit mode selection:
    • :auto - Auto-detect based on position and capabilities (default)
    • :positioned - Force positioned mode (requires :position)
    • :inline - Force inline mode
  • :on_select - Callback when item is selected: fn id -> ... end
  • :on_close - Callback when menu is closed: fn -> ... end
  • :orientation - For inline mode: :horizontal (default) or :vertical
  • :item_style - Style for normal items
  • :selected_style - Style for focused item
  • :disabled_style - Style for disabled items
  • :number_style - For inline mode: style for [n] prefix

Returns

  • {:ok, {module, props}} - The module and props to use
  • {:error, :missing_items} - Items not provided
  • {:error, :missing_position} - Positioned mode requires position
  • {:error, :position_required} - Auto mode with mouse support but no position

create!(opts)

@spec create!(keyword()) :: {module(), map()}

Creates a context menu, raising on error.

Same as create/1 but raises ArgumentError on invalid configuration.

mouse_supported?()

@spec mouse_supported?() :: boolean()

Returns whether the terminal supports mouse tracking.

This is used for auto-detection when no position is provided.