-module(lightspeed@component@stateful).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/component/stateful.gleam").
-export([mount_context/3, route/2, route_event/2, start/4, update/2, handle_event/2, model/1, rendered/1, html/1, context/1]).
-export_type([lifecycle/0, mount_context/0, event_route/1, lifecycle_component/3, instance/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Stateful component lifecycle and event routing compatibility helpers.\n").
-type lifecycle() :: disconnected | connected.
-type mount_context() :: {mount_context, binary(), binary(), lifecycle()}.
-type event_route(HYU) :: {event_route,
binary(),
fun((lightspeed@event:inbound_event()) -> {ok, HYU} |
{error, lightspeed@event:decode_error()})}.
-type lifecycle_component(HYV, HYW, HYX) :: {lifecycle_component,
fun((mount_context(), HYW) -> {HYV,
list(lightspeed@component:command(HYX))}),
fun((HYV, HYW) -> {HYV, list(lightspeed@component:command(HYX))}),
fun((HYV, HYX) -> {HYV, list(lightspeed@component:command(HYX))}),
fun((HYV) -> lightspeed@component:rendered()),
list(event_route(HYX))}.
-opaque instance(HYY, HYZ, HZA) :: {instance,
lifecycle_component(HYY, HYZ, HZA),
HYY,
HYZ,
mount_context(),
binary(),
lightspeed@component:rendered()}.
-file("src/lightspeed/component/stateful.gleam", 50).
?DOC(" Build a mount context.\n").
-spec mount_context(binary(), binary(), lifecycle()) -> mount_context().
mount_context(Id, Route, Lifecycle) ->
{mount_context, Id, Route, Lifecycle}.
-file("src/lightspeed/component/stateful.gleam", 59).
?DOC(" Build one event route.\n").
-spec route(
binary(),
fun((lightspeed@event:inbound_event()) -> {ok, HZB} |
{error, lightspeed@event:decode_error()})
) -> event_route(HZB).
route(Name, Decode) ->
{event_route, Name, Decode}.
-file("src/lightspeed/component/stateful.gleam", 195).
-spec route_names(list(event_route(any()))) -> binary().
route_names(Routes) ->
case Routes of
[] ->
<<"no_routes_registered"/utf8>>;
[{event_route, Name, _}] ->
Name;
[{event_route, Name@1, _} | Rest] ->
<<<<Name@1/binary, "|"/utf8>>/binary, (route_names(Rest))/binary>>
end.
-file("src/lightspeed/component/stateful.gleam", 175).
-spec route_event_with_expected(
lightspeed@event:inbound_event(),
list(event_route(IBU)),
binary()
) -> {ok, IBU} | {error, lightspeed@event:decode_error()}.
route_event_with_expected(Inbound, Routes, Expected) ->
case Routes of
[] ->
{error,
{unexpected_event, Expected, lightspeed@event:name(Inbound)}};
[{event_route, Name, Decode} | Rest] ->
case lightspeed@event:name(Inbound) =:= Name of
true ->
Decode(Inbound);
false ->
route_event_with_expected(Inbound, Rest, Expected)
end
end.
-file("src/lightspeed/component/stateful.gleam", 67).
?DOC(" Resolve an inbound event against named routes.\n").
-spec route_event(lightspeed@event:inbound_event(), list(event_route(HZF))) -> {ok,
HZF} |
{error, lightspeed@event:decode_error()}.
route_event(Inbound, Routes) ->
route_event_with_expected(Inbound, Routes, route_names(Routes)).
-file("src/lightspeed/component/stateful.gleam", 77).
?DOC(
" Start a stateful component instance from mount assigns.\n"
"\n"
" Returns initial commands and one deterministic replace patch.\n"
).
-spec start(lifecycle_component(HZK, HZL, HZM), mount_context(), HZL, binary()) -> {instance(HZK, HZL, HZM),
list(lightspeed@component:command(HZM)),
list(lightspeed@diff:patch())}.
start(Definition, Context, Assigns, Target) ->
{Model, Commands} = (erlang:element(2, Definition))(Context, Assigns),
Rendered = (erlang:element(5, Definition))(Model),
Patch = {replace, Target, lightspeed@component:to_html(Rendered)},
{{instance, Definition, Model, Assigns, Context, Target, Rendered},
Commands,
[Patch]}.
-file("src/lightspeed/component/stateful.gleam", 203).
-spec patch_plan(
binary(),
lightspeed@component:rendered(),
lightspeed@component:rendered()
) -> list(lightspeed@diff:patch()).
patch_plan(Target, Previous, Next) ->
case Previous =:= Next of
true ->
[];
false ->
case lightspeed@component:fingerprint(Previous) =:= lightspeed@component:fingerprint(
Next
) of
true ->
[{update_segments,
Target,
lightspeed@component:fingerprint(Next),
[lightspeed@diff:slot(
<<"html"/utf8>>,
lightspeed@component:to_html(Next)
)]}];
false ->
[{replace, Target, lightspeed@component:to_html(Next)}]
end
end.
-file("src/lightspeed/component/stateful.gleam", 106).
?DOC(" Apply parent assigns updates.\n").
-spec update(instance(HZW, HZX, HZY), HZX) -> {instance(HZW, HZX, HZY),
list(lightspeed@component:command(HZY)),
list(lightspeed@diff:patch())}.
update(Instance, Assigns) ->
{Model, Commands} = (erlang:element(3, erlang:element(2, Instance)))(
erlang:element(3, Instance),
Assigns
),
Rendered = (erlang:element(5, erlang:element(2, Instance)))(Model),
Patches = patch_plan(
erlang:element(6, Instance),
erlang:element(7, Instance),
Rendered
),
{{instance,
erlang:element(2, Instance),
Model,
Assigns,
erlang:element(5, Instance),
erlang:element(6, Instance),
Rendered},
Commands,
Patches}.
-file("src/lightspeed/component/stateful.gleam", 126).
?DOC(" Route and handle one inbound event.\n").
-spec handle_event(instance(IAI, IAJ, IAK), lightspeed@event:inbound_event()) -> {instance(IAI, IAJ, IAK),
{ok, IAK} | {error, lightspeed@event:decode_error()},
list(lightspeed@component:command(IAK)),
list(lightspeed@diff:patch())}.
handle_event(Instance, Inbound) ->
case route_event(Inbound, erlang:element(6, erlang:element(2, Instance))) of
{error, Error} ->
{Instance, {error, Error}, [], []};
{ok, Message} ->
{Model, Commands} = (erlang:element(4, erlang:element(2, Instance)))(
erlang:element(3, Instance),
Message
),
Rendered = (erlang:element(5, erlang:element(2, Instance)))(Model),
Patches = patch_plan(
erlang:element(6, Instance),
erlang:element(7, Instance),
Rendered
),
{{instance,
erlang:element(2, Instance),
Model,
erlang:element(4, Instance),
erlang:element(5, Instance),
erlang:element(6, Instance),
Rendered},
{ok, Message},
Commands,
Patches}
end.
-file("src/lightspeed/component/stateful.gleam", 155).
?DOC(" Current model.\n").
-spec model(instance(IAW, any(), any())) -> IAW.
model(Instance) ->
erlang:element(3, Instance).
-file("src/lightspeed/component/stateful.gleam", 160).
?DOC(" Last rendered value.\n").
-spec rendered(instance(any(), any(), any())) -> lightspeed@component:rendered().
rendered(Instance) ->
erlang:element(7, Instance).
-file("src/lightspeed/component/stateful.gleam", 165).
?DOC(" Latest HTML snapshot.\n").
-spec html(instance(any(), any(), any())) -> binary().
html(Instance) ->
_pipe = erlang:element(7, Instance),
lightspeed@component:to_html(_pipe).
-file("src/lightspeed/component/stateful.gleam", 171).
?DOC(" Current mount context.\n").
-spec context(instance(any(), any(), any())) -> mount_context().
context(Instance) ->
erlang:element(5, Instance).