-module(sprocket@hooks). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/sprocket/hooks.gleam"). -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", 64). -spec maybe_trigger_update( list(gleam@dynamic:dynamic_()), gleam@option:option(list(gleam@dynamic:dynamic_())), GKC, fun(() -> GKC) ) -> {GKC, 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", 34). ?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)) -> {GKA, sprocket@internal@context:element()}) ) -> {GKA, sprocket@internal@context:element()}. callback(Ctx, Callback_fn, Deps, Cb) -> {Ctx@2, Id@1, Current_callback_fn@1, Prev@1, Index@1} = case sprocket@internal@context:fetch_or_init_hook( Ctx, fun() -> {callback, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), Callback_fn, none} end ) of {Ctx@1, {callback, Id, Current_callback_fn, Prev}, Index} -> { Ctx@1, Id, Current_callback_fn, Prev, Index}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"callback"/utf8>>, line => 40, value => _assert_fail, start => 1435, 'end' => 1617, pattern_start => 1446, pattern_end => 1500}) end, {Callback_fn@1, Deps@1} = maybe_trigger_update( Deps, begin _pipe = Prev@1, gleam@option:then( _pipe, fun(Prev@2) -> erlang:element(2, Prev@2) end ) end, Current_callback_fn@1, fun() -> Callback_fn end ), Ctx@3 = sprocket@internal@context:update_hook( Ctx@2, {callback, Id@1, Callback_fn@1, {some, {callback_result, Deps@1}}}, Index@1 ), Cb(Ctx@3, Callback_fn@1). -file("src/sprocket/hooks.gleam", 88). ?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, {Ctx@2, Id@1, Index@1} = case sprocket@internal@context:fetch_or_init_hook( Ctx, Init ) of {Ctx@1, {client, Id, _, _}, Index} -> {Ctx@1, Id, Index}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"client"/utf8>>, line => 99, value => _assert_fail, start => 3034, 'end' => 3136, pattern_start => 3045, pattern_end => 3092}) end, Ctx@3 = sprocket@internal@context:update_hook( Ctx@2, {client, Id@1, Name, Handle_event}, Index@1 ), Bind_hook_attr = fun() -> {client_hook, Id@1, Name} end, Dispatch_event = fun(Kind, Payload) -> sprocket@internal@context:dispatch_client_hook_event( Ctx@3, Id@1, Kind, Payload ) end, Cb(Ctx@3, Bind_hook_attr, Dispatch_event). -file("src/sprocket/hooks.gleam", 116). ?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", 125). ?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, {Ctx@2, Id@1, Prev@1, Index@1} = case sprocket@internal@context:fetch_or_init_hook( Ctx, Init ) of {Ctx@1, {effect, Id, _, _, Prev}, Index} -> {Ctx@1, Id, Prev, Index}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"effect"/utf8>>, line => 137, value => _assert_fail, start => 4376, 'end' => 4481, pattern_start => 4387, pattern_end => 4437}) end, Ctx@3 = sprocket@internal@context:update_hook( Ctx@2, {effect, Id@1, Effect_fn, Deps, Prev@1}, Index@1 ), Cb(Ctx@3). -file("src/sprocket/hooks.gleam", 154). ?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(() -> GKG), list(gleam@dynamic:dynamic_()), fun((sprocket@internal@context:context(), GKG) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}) ) -> {sprocket@internal@context:context(), sprocket@internal@context:element()}. memo(Ctx, Memo_fn, Deps, Cb) -> {Ctx@2, Id@1, Current_memoized@1, Prev@1, Index@1} = case 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 ) of {Ctx@1, {memo, Id, Current_memoized, Prev}, Index} -> { Ctx@1, Id, Current_memoized, Prev, Index}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"memo"/utf8>>, line => 160, value => _assert_fail, start => 5149, 'end' => 5348, pattern_start => 5160, pattern_end => 5215}) end, {Memoized, Deps@1} = maybe_trigger_update( Deps, begin _pipe = Prev@1, gleam@option:then( _pipe, fun(Prev@2) -> erlang:element(2, Prev@2) end ) end, Current_memoized@1, fun() -> gleam_stdlib:identity(Memo_fn()) end ), Ctx@3 = sprocket@internal@context:update_hook( Ctx@2, {memo, Id@1, Memoized, {some, {memo_result, Deps@1}}}, Index@1 ), Cb(Ctx@3, sprocket@internal@utils@unsafe_coerce:unsafe_coerce(Memoized)). -file("src/sprocket/hooks.gleam", 195). ?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", 210). ?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", 220). ?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((GKL) -> nil)) -> GKK), fun((GKK, GKL, fun((GKL) -> nil)) -> GKK), fun((sprocket@internal@context:context(), GKK, fun((GKL) -> 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() -> Reducer_actor@1 = case 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 of {ok, Reducer_actor} -> Reducer_actor; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"reducer"/utf8>>, line => 231, value => _assert_fail, start => 7591, 'end' => 7827, pattern_start => 7602, pattern_end => 7619}) end, {reducer, sprocket@internal@utils@unique:cuid(erlang:element(9, Ctx)), gleam_stdlib:identity(Reducer_actor@1), fun() -> sprocket@internal@reducer:shutdown(Reducer_actor@1) end} end, {Ctx@2, Dyn_reducer_actor@1} = case sprocket@internal@context:fetch_or_init_hook( Ctx, Reducer_init ) of {Ctx@1, {reducer, _, Dyn_reducer_actor, _}, _} -> { Ctx@1, Dyn_reducer_actor}; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"reducer"/utf8>>, line => 245, value => _assert_fail@1, start => 7983, 'end' => 8111, pattern_start => 7994, pattern_end => 8059}) end, Reducer_actor@2 = sprocket@internal@utils@unsafe_coerce:unsafe_coerce( Dyn_reducer_actor@1 ), Model = sprocket@internal@reducer:get_model(Reducer_actor@2), Cb( Ctx@2, Model, fun(_capture) -> sprocket@internal@reducer:dispatch(Reducer_actor@2, _capture) end ). -file("src/sprocket/hooks.gleam", 263). ?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(), GKQ, fun((sprocket@internal@context:context(), GKQ, fun((GKQ) -> 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, {Ctx@2, Hook_id@1, Value@1} = case sprocket@internal@context:fetch_or_init_hook( Ctx, Init_state ) of {Ctx@1, {state, Hook_id, Value}, _} -> {Ctx@1, Hook_id, Value}; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/hooks"/utf8>>, function => <<"state"/utf8>>, line => 278, value => _assert_fail, start => 9100, 'end' => 9206, pattern_start => 9111, pattern_end => 9156}) end, Setter = fun(Value@2) -> Update_hook(Hook_id@1, fun(Hook) -> case Hook of {state, Id, _} when Id =:= Hook_id@1 -> {state, Id, gleam_stdlib:identity(Value@2)}; _ -> sprocket@internal@exceptions:throw_on_unexpected_hook_result( Hook ) end end), Trigger_reconciliation() end, Cb( Ctx@2, sprocket@internal@utils@unsafe_coerce:unsafe_coerce(Value@1), Setter ).