TermUI.Focus.Traversal (TermUI v0.2.0)

View Source

Focus traversal utilities for calculating tab order.

Provides utilities for determining the order in which components receive focus during Tab/Shift+Tab navigation.

Tab Order

Components are ordered by:

  1. Explicit tab_index (lower numbers first)
  2. Screen position (top-to-bottom, left-to-right)

Usage

# Get tab order for components
order = Traversal.calculate_order(component_ids)

# Check if component should be skipped
Traversal.should_skip?(component_id)

Summary

Functions

Calculates the tab order for a list of components.

Filters a list to only focusable components.

Gets the next component in tab order.

Gets the previous component in tab order.

Checks if a component should be skipped during traversal.

Functions

calculate_order(component_ids, opts \\ [])

@spec calculate_order(
  [term()],
  keyword()
) :: [term()]

Calculates the tab order for a list of components.

Returns components sorted by tab index, then by position.

Parameters

  • component_ids - List of component ids
  • opts - Options:
    • :tab_indices - Map of component_id => tab_index

Returns

Sorted list of component ids.

filter_focusable(component_ids, opts \\ [])

@spec filter_focusable(
  [term()],
  keyword()
) :: [term()]

Filters a list to only focusable components.

Parameters

  • component_ids - List of component ids
  • opts - Options passed to should_skip?/2

Returns

Filtered list of focusable component ids.

next(ordered_list, current)

@spec next([term()], term() | nil) :: term() | nil

Gets the next component in tab order.

Parameters

  • ordered_list - Components in tab order
  • current - Currently focused component (or nil)

Returns

Next component id, wrapping to first if at end.

prev(ordered_list, current)

@spec prev([term()], term() | nil) :: term() | nil

Gets the previous component in tab order.

Parameters

  • ordered_list - Components in tab order
  • current - Currently focused component (or nil)

Returns

Previous component id, wrapping to last if at beginning.

should_skip?(component_id, opts \\ [])

@spec should_skip?(
  term(),
  keyword()
) :: boolean()

Checks if a component should be skipped during traversal.

A component is skipped if:

  • It has focusable: false
  • It has disabled: true
  • It has a negative tab_index

Parameters

  • component_id - Component to check
  • opts - Options:
    • :focusable - Map of component_id => boolean
    • :disabled - Map of component_id => boolean
    • :tab_indices - Map of component_id => integer

Returns

Boolean indicating if component should be skipped.