-module(sprocket@hooks). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([callback/4, client/4, dep/1, effect/4, memo/4, provider/3, provide/3, reducer/4, state/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. -file("src/sprocket/hooks.gleam", 63). -spec maybe_trigger_update( list(gleam@dynamic:dynamic_()), gleam@option:option(list(gleam@dynamic:dynamic_())), KJC, fun(() -> KJC) ) -> {KJC, gleam@option:option(list(gleam@dynamic:dynamic_()))}. maybe_trigger_update(Deps, Prev, Value, Updater) -> case Prev of {some, Prev_deps} -> case sprocket@internal@context:compare_deps(Prev_deps, Deps) of {changed, New_deps} -> {Updater(), {some, New_deps}}; unchanged -> {Value, Prev} end; none -> {Updater(), {some, Deps}} end. -file("src/sprocket/hooks.gleam", 33). ?DOC( " Callback Hook\n" " -------------\n" " Creates a callback hook that will return a cached version of a given callback\n" " function and only recompute the callback when specified dependencies change.\n" " \n" " This hook is useful for when a component needs to use a callback function that\n" " is referenced as a dependency by another hook, such as an effect hook.\n" ). -spec callback( sprocket@internal@context:context(), fun(() -> nil), list(gleam@dynamic:dynamic_()), fun((sprocket@internal@context:context(), fun(() -> nil)) -> {KJA, sprocket@internal@context:element()}) ) -> {KJA, sprocket@internal@context:element()}. callback(Ctx, Callback_fn, Deps, Cb) -> _assert_subject = sprocket@internal@context:fetch_or_init_hook( Ctx, fun() -> {callback, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), Callback_fn, none} end ), {Ctx@1, {callback, Id, Current_callback_fn, Prev}, Index} = case _assert_subject of {_, {callback, _, _, _}, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"callback"/utf8>>, line => 39}) end, {Callback_fn@1, Deps@1} = maybe_trigger_update( Deps, begin _pipe = Prev, gleam@option:then( _pipe, fun(Prev@1) -> erlang:element(2, Prev@1) end ) end, Current_callback_fn, fun() -> Callback_fn end ), Ctx@2 = sprocket@internal@context:update_hook( Ctx@1, {callback, Id, Callback_fn@1, {some, {callback_result, Deps@1}}}, Index ), Cb(Ctx@2, Callback_fn@1). -file("src/sprocket/hooks.gleam", 87). ?DOC( " Client Hook\n" " -----------\n" " Creates a client hook that can be used to facilitate communication with a client\n" " (such as a web browser). The client hook functionality is defined by the client\n" " and is typically used to send or receive messages to/from the client.\n" ). -spec client( sprocket@internal@context:context(), binary(), gleam@option:option(fun((binary(), gleam@dynamic:dynamic_(), fun((binary(), gleam@option:option(gleam@dynamic:dynamic_())) -> nil)) -> nil)), fun((sprocket@internal@context:context(), fun(() -> sprocket@internal@context:attribute()), fun((binary(), gleam@option:option(gleam@dynamic:dynamic_())) -> nil)) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. client(Ctx, Name, Handle_event, Cb) -> Init = fun() -> {client, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), Name, Handle_event} end, _assert_subject = sprocket@internal@context:fetch_or_init_hook(Ctx, Init), {Ctx@1, {client, Id, _, _}, Index} = case _assert_subject of {_, {client, _, _, _}, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"client"/utf8>>, line => 98}) end, Ctx@2 = sprocket@internal@context:update_hook( Ctx@1, {client, Id, Name, Handle_event}, Index ), Bind_hook_attr = fun() -> {client_hook, Id, Name} end, Dispatch_event = fun(Kind, Payload) -> sprocket@internal@context:dispatch_client_hook_event( Ctx@2, Id, Kind, Payload ) end, Cb(Ctx@2, Bind_hook_attr, Dispatch_event). -file("src/sprocket/hooks.gleam", 115). ?DOC(" Creates a hook dependency from some value\n"). -spec dep(any()) -> gleam@dynamic:dynamic_(). dep(Dependency) -> gleam_stdlib:identity(Dependency). -file("src/sprocket/hooks.gleam", 124). ?DOC( " Effect Hook\n" " -----------\n" " Creates an effect hook that will run the given effect function when the deps change. The effect\n" " function is memoized and recomputed when the deps change. The effect function can return a cleanup\n" " function that will be called when the effect is removed.\n" ). -spec effect( sprocket@internal@context:context(), fun(() -> gleam@option:option(fun(() -> nil))), list(gleam@dynamic:dynamic_()), fun((sprocket@internal@context:context()) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. effect(Ctx, Effect_fn, Deps, Cb) -> Init = fun() -> {effect, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), Effect_fn, Deps, none} end, _assert_subject = sprocket@internal@context:fetch_or_init_hook(Ctx, Init), {Ctx@1, {effect, Id, _, _, Prev}, Index} = case _assert_subject of {_, {effect, _, _, _, _}, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"effect"/utf8>>, line => 136}) end, Ctx@2 = sprocket@internal@context:update_hook( Ctx@1, {effect, Id, Effect_fn, Deps, Prev}, Index ), Cb(Ctx@2). -file("src/sprocket/hooks.gleam", 153). ?DOC( " Memo Hook\n" " ---------\n" " Creates a memo hook that can be used to memoize the result of a function. The memo\n" " hook will return the result of the function and will only recompute the result when\n" " the dependencies change.\n" " \n" " This hook is useful for optimizing performance by memoizing the result of an\n" " expensive function between renders.\n" ). -spec memo( sprocket@internal@context:context(), fun(() -> KJG), list(gleam@dynamic:dynamic_()), fun((sprocket@internal@context:context(), KJG) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. memo(Ctx, Memo_fn, Deps, Cb) -> _assert_subject = sprocket@internal@context:fetch_or_init_hook( Ctx, fun() -> {memo, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), gleam_stdlib:identity(Memo_fn()), none} end ), {Ctx@1, {memo, Id, Current_memoized, Prev}, Index} = case _assert_subject of {_, {memo, _, _, _}, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"memo"/utf8>>, line => 159}) end, {Memoized, Deps@1} = maybe_trigger_update( Deps, begin _pipe = Prev, gleam@option:then( _pipe, fun(Prev@1) -> erlang:element(2, Prev@1) end ) end, Current_memoized, fun() -> gleam_stdlib:identity(Memo_fn()) end ), Ctx@2 = sprocket@internal@context:update_hook( Ctx@1, {memo, Id, Memoized, {some, {memo_result, Deps@1}}}, Index ), Cb(Ctx@2, sprocket@internal@utils@unsafe_coerce:unsafe_coerce(Memoized)). -file("src/sprocket/hooks.gleam", 194). ?DOC( " Provider Hook\n" " ------------\n" " Creates a provider hook that allows a component to access data from a parent or ancestor component.\n" " The provider hook will return an optional containing the current value provided from an ancestor using\n" " a given provider function. If the provider hook is called from a context that does not have a matching\n" " provider, the hook will return `None`.\n" " \n" " The ancestor provides the value by using a custom provider that is unique to the provider hook. This\n" " custom provider is created using `provider` function in the `sprocket/internal/context` module.\n" " \n" " This hook is conceptually similar to the `useContext` hook in React.\n" ). -spec provider( sprocket@internal@context:context(), binary(), fun((sprocket@internal@context:context(), gleam@option:option(any())) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. provider(Ctx, Key, Cb) -> Value = begin _pipe = erlang:element(10, Ctx), _pipe@1 = gleam_stdlib:map_get(_pipe, Key), _pipe@2 = gleam@option:from_result(_pipe@1), gleam@option:map( _pipe@2, fun(V) -> sprocket@internal@utils@unsafe_coerce:unsafe_coerce(V) end ) end, Cb(Ctx, Value). -file("src/sprocket/hooks.gleam", 209). ?DOC(" Creates a new provider element with the given key and value.\n"). -spec provide(binary(), any(), sprocket@internal@context:element()) -> sprocket@internal@context:element(). provide(Key, Value, Element) -> {provider, Key, gleam_stdlib:identity(Value), Element}. -file("src/sprocket/hooks.gleam", 219). ?DOC( " Reducer Hook\n" " ------------\n" " Creates a reducer hook that can be used to manage state. The reducer hook will\n" " return the current state of the reducer and a dispatch function that can be used\n" " to update the reducer's state. Dispatching a message to the reducer will result\n" " in a re-render of the component.\n" ). -spec reducer( sprocket@internal@context:context(), fun((fun((KJL) -> nil)) -> KJK), fun((KJK, KJL, fun((KJL) -> nil)) -> KJK), fun((sprocket@internal@context:context(), KJK, fun((KJL) -> nil)) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. reducer(Ctx, Initialize, Update, Cb) -> {context, _, _, _, _, Trigger_reconciliation, _, _, _, _} = Ctx, Reducer_init = fun() -> _assert_subject = begin _pipe = sprocket@internal@reducer:start( Initialize, Update, fun(_) -> Trigger_reconciliation() end ), gleam@result:map_error( _pipe, fun(Error) -> sprocket@internal@logger:error( <<"hooks.reducer: failed to start reducer actor"/utf8>> ), Error end ) end, {ok, Reducer_actor} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"reducer"/utf8>>, line => 230}) end, {reducer, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), gleam_stdlib:identity(Reducer_actor), fun() -> sprocket@internal@reducer:shutdown(Reducer_actor) end} end, _assert_subject@1 = sprocket@internal@context:fetch_or_init_hook( Ctx, Reducer_init ), {Ctx@1, {reducer, _, Dyn_reducer_actor, _}, _} = case _assert_subject@1 of {_, {reducer, _, _, _}, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@1, module => <<"sprocket/hooks"/utf8>>, function => <<"reducer"/utf8>>, line => 244}) end, Reducer_actor@1 = sprocket@internal@utils@unsafe_coerce:unsafe_coerce( Dyn_reducer_actor ), Model = sprocket@internal@reducer:get_model(Reducer_actor@1), Cb( Ctx@1, Model, fun(_capture) -> sprocket@internal@reducer:dispatch(Reducer_actor@1, _capture) end ). -file("src/sprocket/hooks.gleam", 262). ?DOC( " State Hook\n" " ----------\n" " Creates a state hook that can be used to manage state. The state hook will return\n" " the current state and a setter function that can be used to update the state. Setting\n" " the state will result in a re-render of the component.\n" ). -spec state( sprocket@internal@context:context(), KJQ, fun((sprocket@internal@context:context(), KJQ, fun((KJQ) -> nil)) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. state(Ctx, Initial, Cb) -> {context, _, _, _, _, Trigger_reconciliation, Update_hook, _, _, _} = Ctx, Init_state = fun() -> {state, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), gleam_stdlib:identity(Initial)} end, _assert_subject = sprocket@internal@context:fetch_or_init_hook( Ctx, Init_state ), {Ctx@1, {state, Hook_id, Value}, _} = case _assert_subject of {_, {state, _, _}, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"sprocket/hooks"/utf8>>, function => <<"state"/utf8>>, line => 277}) end, Setter = fun(Value@1) -> Update_hook(Hook_id, fun(Hook) -> case Hook of {state, Id, _} when Id =:= Hook_id -> {state, Id, gleam_stdlib:identity(Value@1)}; _ -> sprocket@internal@exceptions:throw_on_unexpected_hook_result( Hook ) end end), Trigger_reconciliation() end, Cb( Ctx@1, sprocket@internal@utils@unsafe_coerce:unsafe_coerce(Value), Setter ).