Packages

Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.

Current section

Files

Jump to
raxol lib raxol core renderer view layout_helpers.ex
Raw

lib/raxol/core/renderer/view/layout_helpers.ex

defmodule Raxol.Core.Renderer.View.LayoutHelpers do
@moduledoc """
Layout helper functions for the View module.
Extracted from the main View module to improve maintainability.
"""
@doc """
Calculates flex layout dimensions based on the given constraints.
Returns a map with calculated width and height.
"""
@spec flex(map()) :: %{width: integer(), height: integer()}
def flex(constraints) do
%{
width: calculate_flex_width(constraints),
height: calculate_flex_height(constraints)
}
end
@doc """
Creates a new panel view (box with border and children).
## Options
* `:children` - Child views
* `:border` - Border style (default: :single)
* `:padding` - Padding inside the panel (default: 1)
* `:style` - Additional style options
* `:title` - Optional title for the panel
* `:fg` - Foreground color
* `:bg` - Background color
## Examples
LayoutHelpers.panel(children: [View.text("Hello")])
LayoutHelpers.panel(border: :double, title: "Panel")
NOTE: Only panel/1 (with a keyword list) is supported. Update any panel/2 usages to panel/1.
"""
def panel(opts \\ []) do
unless Keyword.keyword?(opts) do
raise ArgumentError,
"LayoutHelpers.panel macro expects a keyword list as the first argument, got: #{inspect(opts)}"
end
opts
|> build_panel_opts()
|> Raxol.Core.Renderer.View.box()
end
defp build_panel_opts(opts) do
base = [
border: Keyword.get(opts, :border, :single),
padding: Keyword.get(opts, :padding, 1),
children: Keyword.get(opts, :children, []),
fg: Keyword.get(opts, :fg),
bg: Keyword.get(opts, :bg)
]
base
|> maybe_add_panel_opt(:title, Keyword.get(opts, :title))
|> maybe_add_panel_opt(:style, Keyword.get(opts, :style, []))
end
defp maybe_add_panel_opt(opts, _key, nil), do: opts
defp maybe_add_panel_opt(opts, :style, []), do: opts
defp maybe_add_panel_opt(opts, key, value), do: Keyword.put(opts, key, value)
# Private helper functions
@spec calculate_flex_width(any()) :: any()
defp calculate_flex_width(constraints) do
case constraints do
%{width: :auto, flex: flex} when flex > 0 ->
# Calculate width based on flex grow
trunc(constraints.available_width * (flex / constraints.total_flex))
%{width: width} when is_integer(width) ->
# Fixed width
width
_ ->
# Default to available width
constraints.available_width
end
end
@spec calculate_flex_height(any()) :: any()
defp calculate_flex_height(constraints) do
case constraints do
%{height: :auto, flex: flex} when flex > 0 ->
# Calculate height based on flex grow
trunc(constraints.available_height * (flex / constraints.total_flex))
%{height: height} when is_integer(height) ->
# Fixed height
height
_ ->
# Default to available height
constraints.available_height
end
end
end