Current section
Files
Jump to
Current section
Files
lib/emerge.ex
defmodule Emerge do
@moduledoc """
Public API for writing viewport modules.
Use `Emerge` for modules that mount viewport state or options, define UI with
`render/0` or `render/1`, handle input, and request rerenders.
`use Emerge` also brings the common `Emerge.UI` helpers into scope, so
viewport modules can declare trees directly or call regular Elixir functions
that return `Emerge.tree()`.
It also aliases `Emerge` as `Viewport`, which makes callbacks and helper
calls such as `@impl Viewport` and `Viewport.rerender(state)` available
inside the module.
Viewport state is a plain map. Emerge keeps its runtime metadata under the
reserved `:__emerge__` key.
Element event helpers such as `Event.on_press/1`, `Event.on_click/1`, and
`Event.on_swipe_right/1`
deliver regular process messages and are usually handled in `handle_info/2`.
Implement `handle_input/2` when you want to react to raw input events coming
from the renderer.
`use Emerge` stops the viewport by default when Wayland sends a close request.
Override `handle_close/2` to customize that behavior.
For retained-tree diffing, encoding, and event routing helpers, see
`Emerge.Engine`.
"""
alias Emerge.Runtime.Viewport, as: RuntimeViewport
@typedoc "Public tree type built with `Emerge.UI` and rendered by Emerge backends."
@type tree :: Emerge.Engine.Element.t()
@typedoc "Viewport state map passed to render/1 and callback functions."
@type state :: map()
@callback mount(keyword()) :: {:ok, state(), keyword()} | {:ok, keyword()} | {:stop, term()}
@callback render() :: tree()
@callback render(state()) :: tree()
@callback handle_info(term(), state()) ::
{:noreply, state()} | {:stop, term(), state()}
@callback handle_input(term(), state()) ::
{:noreply, state()} | {:stop, term(), state()}
@callback handle_close(term(), state()) ::
{:noreply, state()} | {:stop, term(), state()}
@callback wrap_payload(term(), term(), term()) :: term()
@optional_callbacks render: 0,
render: 1,
handle_info: 2,
handle_input: 2,
handle_close: 2,
wrap_payload: 3
defmacro __using__(_opts) do
quote do
use Emerge.UI
alias Emerge, as: Viewport
@behaviour Emerge
def start_link(opts \\ []) do
Emerge.Runtime.Viewport.start_link(__MODULE__, opts)
end
def child_spec(opts) do
Emerge.Runtime.Viewport.child_spec(__MODULE__, opts)
end
@impl Emerge
def handle_input(event, state)
def handle_input(_event, state), do: {:noreply, state}
@impl Emerge
def handle_close(_reason, state), do: {:stop, :normal, state}
@impl Emerge
def wrap_payload(message, payload, event_type) do
Emerge.default_wrap_payload(message, payload, event_type)
end
defoverridable handle_input: 2, handle_close: 2, wrap_payload: 3
end
end
@spec notify_source_reloaded(term()) :: :ok
def notify_source_reloaded(meta \\ %{}) do
RuntimeViewport.notify_source_reloaded(meta)
end
@spec renderer(pid()) :: term()
def renderer(pid) when is_pid(pid) do
RuntimeViewport.renderer(pid)
end
@spec rerender(state()) :: state()
def rerender(state) when is_map(state) do
RuntimeViewport.rerender(state)
end
@spec default_wrap_payload(term(), term(), term()) :: term()
def default_wrap_payload(message, payload, event_type) do
RuntimeViewport.default_wrap_payload(message, payload, event_type)
end
end