-module(sketch@lustre). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/sketch/lustre.gleam"). -export([setup/0, construct/1, teardown/1, render/3, node/0, ssr/1]). -export_type([container/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -opaque container() :: {document, gleam@dynamic:dynamic_()} | {shadow, gleam@dynamic:dynamic_()} | node. -file("src/sketch/lustre.gleam", 38). ?DOC( " Setup the StyleSheet to use across your application. At least one stylesheet\n" " must be set in your entire application. `setup` should be called once for\n" " every stylesheet you'll use.\n" "\n" " In `sketch_lustre`, there's no notion of persistent or ephemeral stylesheets:\n" " all stylesheets will be persisted in the application.\n" "\n" " In case you need to add initial styling directly in your stylesheet, take a\n" " look at [`construct`](#construct).\n" "\n" " ```gleam\n" " pub fn main() {\n" " let assert Ok(stylesheet) = sketch_lustre.setup()\n" " // The following code goes there.\n" " }\n" " ```\n" ). -spec setup() -> {ok, sketch:style_sheet()} | {error, nil}. setup() -> case sketch:stylesheet(persistent) of {error, _} -> {error, nil}; {ok, Stylesheet} -> sketch_global_ffi:set_stylesheet(Stylesheet) end. -file("src/sketch/lustre.gleam", 64). ?DOC( " Setup the StyleSheet to use across your application, and let you inject\n" " initial styling directly in your stylesheet. If you don't need to add\n" " default styling, you can take a look at [`setup`](#setup).\n" "\n" " In `sketch_lustre`, there's no notion of persistent or ephemeral stylesheets:\n" " all stylesheets will be persisted in the application.\n" "\n" " ```gleam\n" " pub fn main() {\n" " let assert Ok(stylesheet) =\n" " sketch_lustre.construct(fn (stylesheet) {\n" " stylesheet\n" " |> sketch.global(css.global(\"html\", [...]))\n" " |> sketch.global(css.global(\"body\", [...]))\n" " |> sketch.global(css.global(\":root\", [...]))\n" " })\n" " // The following code goes there.\n" " }\n" " ```\n" ). -spec construct(fun((sketch:style_sheet()) -> sketch:style_sheet())) -> {ok, sketch:style_sheet()} | {error, nil}. construct(Init) -> case sketch:stylesheet(persistent) of {error, _} -> {error, nil}; {ok, Stylesheet} -> sketch_global_ffi:set_stylesheet(Init(Stylesheet)) end. -file("src/sketch/lustre.gleam", 84). ?DOC( " Unref the StyleSheet to let it be garbaged by the runtime. Because stylesheets\n" " are memoized to guarantee performance and usability of Sketch Lustre, they\n" " should be dereferenced to ensure no memory leaks will happen in the application.\n" "\n" " ```gleam\n" " pub fn main() {\n" " let assert Ok(stylesheet) = sketch_lustre.setup()\n" " ...\n" " let assert Ok(_) = sketch_lustre.teardown(stylesheet)\n" " }\n" " ```\n" ). -spec teardown(sketch:style_sheet()) -> {ok, nil} | {error, nil}. teardown(Stylesheet) -> gleam@result:map( sketch_global_ffi:teardown_stylesheet(Stylesheet), fun(_) -> sketch:dispose(Stylesheet) end ). -file("src/sketch/lustre.gleam", 112). ?DOC( " Use `render` as a view middleware. Like in Wisp, `sketch_lustre`\n" " adopts the middleware philosophy in Lustre, and allows you to call `render`\n" " directly in your view function, by using `use`. No need to wrap your view\n" " function.\n" "\n" " ```gleam\n" " import lustre\n" " import lustre/element\n" " import sketch\n" " import sketch/lustre as sketch_lustre\n" " import sketch/lustre/element/html\n" "\n" " pub fn main() {\n" " let assert Ok(stylesheet) = sketch_lustre.setup()\n" " lustre.simple(init, update, view(_, stylesheet))\n" " |> lustre.start(\"#root\", Nil)\n" " }\n" "\n" " fn view(model: model, stylesheet: sketch.StyleSheet) -> element.Element(msg) {\n" " use <- skech_lustre.render(stylesheet, in: [sketch_lustre.node()])\n" " html.div([], [])\n" " }\n" " ```\n" ). -spec render( sketch:style_sheet(), list(container()), fun(() -> lustre@vdom@vnode:element(OYD)) ) -> lustre@vdom@vnode:element(OYD). render(Stylesheet, Outputs, View) -> case sketch_global_ffi:set_current_stylesheet(Stylesheet) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sketch/lustre"/utf8>>, function => <<"render"/utf8>>, line => 117, value => _assert_fail, start => 3944, 'end' => 4004, pattern_start => 3955, pattern_end => 3960}) end, New_view = View(), case sketch_global_ffi:get_stylesheet() of {error, _} -> New_view; {ok, Stylesheet@1} -> Content = sketch:render(Stylesheet@1), gleam@list:fold( Outputs, New_view, fun(View@1, Stylesheet@2) -> case Stylesheet@2 of node -> lustre@element:fragment( [lustre@element@html:style([], Content), View@1] ); {document, Css_stylesheet} -> gleam@function:tap( View@1, fun(_) -> _ = sketch_global_ffi:dismiss_current_stylesheet( ), sketch@lustre@internals@css_stylesheet:replace( Content, Css_stylesheet ) end ); {shadow, Css_stylesheet} -> gleam@function:tap( View@1, fun(_) -> _ = sketch_global_ffi:dismiss_current_stylesheet( ), sketch@lustre@internals@css_stylesheet:replace( Content, Css_stylesheet ) end ) end end ) end. -file("src/sketch/lustre.gleam", 211). ?DOC( " Create a container in the window document. Create a `CSSStyleSheet` and\n" " updates the content directly inside. \\\n" " Because `document` is only accessible in the browser, that function cannot\n" " be called on Erlang target.\n" " Create a container in a Shadow Root. Create a `CSSStyleSheet` and\n" " updates the content directly inside. \\\n" " Because `document` is only accessible in the browser, that function cannot\n" " be called on Erlang target.\n" " Create a container directly in the DOM. CSS will be put directly in the\n" " elements tree, in a `