Behaviour implemented by stateful renderer extensions.
An implicit owns state for an element without requiring the parent view to
handle every interaction itself. It must implement init/3 and
handle_modifiers/3. Event handling and animation are optional.
Initialization
children is a list of attribute maps for elements owned by the implicit.
root_attrs is the implicit root's attribute map with :id included.
last_state is the state from the preceding render; once layout is known it
also contains the previous Breeze.Viewport under :__element__.
An initializer can return the state directly, {:ok, state}, or
{:ok, state, options}. The options are:
:rerender_every- a positive interval in milliseconds for asynchronousanimate/5calls. It has no effect unlessanimate/5is implemented.:active_when_pending- run periodic animation only while an input event is pending. If this and:active_when_focusedare both true, pending state takes precedence.:active_when_focused- run periodic animation only while the implicit root is focused.:captures_keys-trueto capture every key, or a list of key names to capture selectively.:captures_printable_keys- capture printable input and supported text editing keys.:captures_control_keys- capture control-modified key input.:captures_focus_keys- capture Tab and Shift-Tab input.:requires_layout_rerender- rerender after the implicit's dimensions change so layout-dependent state can settle.:state_change_requires_rerender- set tofalsewhen changing only the implicit state does not require another render. The default istrue.
Events
handle_event/3 receives a reserved event-kind argument, the event payload,
and the current implicit state. Breeze adds the target's Breeze.Viewport to
the payload as "element" when one is available.
Every reply stores the returned state. {:noreply, state} stops there.
{{:change, event}, state} and {{:submit, event}, state} route event through
the root element's br-change or br-submit handler. A change reply may also
contain focus: id (or focus: nil) as its third element. Finally,
{{:delegate, id}, state} sends the original event to another implicit.
Render modifiers
handle_modifiers/3 runs for the implicit root and each owned child during
rendering. Its first argument is :root or :child; its second is the
element's attribute keyword list, with :layout_element added when a previous
Breeze.Viewport is available.
It returns a keyword list. style: value adds a binary, map, or list of style
modifiers. scroll_y: top, scroll_x: left, and
scroll: {top, left} control the viewport offset. Any other atom/value pair
becomes a renderer flag; common examples include selected: true,
default_focus: true, and focus_scope: :trap.
Animation
animate/5 receives the element type, its rendered BackBreeze.Box, the
element flags, implicit state, and a context map. It may return a box directly,
{:ok, box}, or {:ok, box, options}. The only animation option is
overlays: overlays; overlays are applied during asynchronous animation
passes.
Breeze calls animate/5 for roots and children during a normal render.
:rerender_every additionally schedules lightweight asynchronous calls for
the root. The context contains :phase, :frame, :now, :pending?,
:focused?, :last_render_at, :last_interaction_at, :theme, :id, and
:layout.
Summary
Types
Runtime context supplied to animate/5.
An option returned from an animation pass.
A valid return value from animate/5.
Attributes collected from an implicit element.
The implicit root or one of its child elements.
An option returned with an implicit event action.
A valid return value from handle_event/3.
Renderer flags attached to an implicit element.
An option returned while initializing implicit state.
A valid return value from init/3.
A decoded terminal key name.
A style, scroll, or state modifier returned during rendering.
State owned by an implicit implementation.
Callbacks
Transforms a rendered box during the normal render or a periodic animation pass.
Handles an event captured by the implicit and returns its next state and action.
Returns renderer modifiers for the implicit root or one of its children.
Initializes state from the owned children, root attributes, and previous state.
Types
@type animation_context() :: %{ phase: :base | :async, frame: non_neg_integer(), now: integer() | nil, pending?: boolean(), focused?: boolean(), last_render_at: integer() | nil, last_interaction_at: integer() | nil, theme: Breeze.Theme.t(), id: String.t() | nil, layout: Breeze.Viewport.t() | nil }
Runtime context supplied to animate/5.
@type animation_option() :: {:overlays, [map()]}
An option returned from an animation pass.
@type animation_reply() :: %BackBreeze.Box{ bottom: term(), children: term(), content: term(), display: term(), fixed_layer_map: term(), height: term(), layer: term(), layer_map: term(), left: term(), overlay?: term(), position: term(), right: term(), scroll: term(), state: term(), style: term(), top: term(), width: term() } | {:ok, %BackBreeze.Box{ bottom: term(), children: term(), content: term(), display: term(), fixed_layer_map: term(), height: term(), layer: term(), layer_map: term(), left: term(), overlay?: term(), position: term(), right: term(), scroll: term(), state: term(), style: term(), top: term(), width: term() }} | {:ok, %BackBreeze.Box{ bottom: term(), children: term(), content: term(), display: term(), fixed_layer_map: term(), height: term(), layer: term(), layer_map: term(), left: term(), overlay?: term(), position: term(), right: term(), scroll: term(), state: term(), style: term(), top: term(), width: term() }, [animation_option()]}
A valid return value from animate/5.
@type attributes() :: map()
Attributes collected from an implicit element.
@type element_type() :: :root | :child
The implicit root or one of its child elements.
@type event_option() :: {:focus, String.t() | nil}
An option returned with an implicit event action.
@type event_reply() :: {:noreply, state()} | {{:change, map()}, state()} | {{:change, map()}, state(), [event_option()]} | {{:submit, map()}, state()} | {{:delegate, String.t()}, state()}
A valid return value from handle_event/3.
@type flags() :: keyword()
Renderer flags attached to an implicit element.
@type init_option() :: {:rerender_every, pos_integer()} | {:active_when_pending, boolean()} | {:active_when_focused, boolean()} | {:captures_keys, boolean() | [key_name()]} | {:captures_printable_keys, boolean()} | {:captures_control_keys, boolean()} | {:captures_focus_keys, boolean()} | {:requires_layout_rerender, boolean()} | {:state_change_requires_rerender, boolean()}
An option returned while initializing implicit state.
@type init_result() :: state() | {:ok, state()} | {:ok, state(), [init_option()]}
A valid return value from init/3.
@type key_name() :: String.t()
A decoded terminal key name.
@type modifier() :: {:style, binary() | map() | list()} | {:scroll_y, integer()} | {:scroll_x, integer()} | {:scroll, {integer(), integer()}} | {atom(), term()}
A style, scroll, or state modifier returned during rendering.
@type state() :: term()
State owned by an implicit implementation.
Callbacks
@callback animate( element_type(), %BackBreeze.Box{ bottom: term(), children: term(), content: term(), display: term(), fixed_layer_map: term(), height: term(), layer: term(), layer_map: term(), left: term(), overlay?: term(), position: term(), right: term(), scroll: term(), state: term(), style: term(), top: term(), width: term() }, flags(), state(), animation_context() ) :: animation_reply()
Transforms a rendered box during the normal render or a periodic animation pass.
@callback handle_event(term(), map(), state()) :: event_reply()
Handles an event captured by the implicit and returns its next state and action.
@callback handle_modifiers(element_type(), flags(), state()) :: [modifier()]
Returns renderer modifiers for the implicit root or one of its children.
@callback init([attributes()], attributes(), state()) :: init_result()
Initializes state from the owned children, root attributes, and previous state.