aboutsummaryrefslogtreecommitdiff
path: root/docs/public/page/api/lustre.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/public/page/api/lustre.md')
-rw-r--r--docs/public/page/api/lustre.md195
1 files changed, 195 insertions, 0 deletions
diff --git a/docs/public/page/api/lustre.md b/docs/public/page/api/lustre.md
new file mode 100644
index 0000000..7ec5021
--- /dev/null
+++ b/docs/public/page/api/lustre.md
@@ -0,0 +1,195 @@
+# lustre
+
+## Applications
+
+### App | erlang javascript
+
+```gleam
+pub type App(flags, model, msg)
+```
+
+The `App` type represents all the parts that make up a Lustre program in the
+Model-View-Update architecture along with the runtime necessary to run it.
+
+Although the type itself is exposed to both the Erlang and JavaScript targets,
+the functions in this module to construct an `App` are only available in the
+JavaScript target, and `start` will only succeed when ran in the browser.
+
+In the future we may have a way to run Lustre applications on the backend, if
+you have any ideas on how to achieve this I'd love to hear about them!
+
+### Error | erlang javascript
+
+```gleam
+pub type Error {
+ AppAlreadyStarted
+ AppNotYetStarted
+ BadComponentName
+ ComponentAlreadyRegistered
+ ElementNotFound
+ NotABrowser
+}
+```
+
+The `Error` type represents all the ways that a Lustre program can fail. These
+include things like trying to start an application that has already been started,
+registering a component with a name that is not valid, or trying to start an
+application in a context that is not a browser.
+
+Often you will want to perform a couple of these actions together, and unifying
+the error type makes this easy. In many of the examples we `let assert` that the
+result is `Ok` but if you wanted to be a bit more dilligent you might use
+`result.try` instead:
+
+```gleam
+import gleam/result
+import lustre
+
+pub fn main () {
+ use _ <- result.try(lustre.component("my-component", ...))
+ let app = lustre.application(...)
+ use dispatch <- result.try(lustre.start(app, "[data-lustre-app]", Nil))
+
+ ...
+}
+```
+
+### element | javascript
+
+```gleam
+pub fn element(el: Element(msg)) -> App(Nil, Nil, msg)
+```
+
+An `element` application is the simplest kind of Lustre program. It takes an
+`Element` to render and renders it to the DOM. These applications hold no state
+and do not respond to messages, but that doesn't mean they are not interactive!
+
+It is possible for [`components`](#component) to be rendered inside an
+`element` application, and these components can be interactive with their own
+contained state and update loops.
+
+### simple | javascript
+
+```gleam
+pub fn simple(
+ init: fn(flags) -> model,
+ update: fn(model, msg) -> model,
+ view: fn(model) -> Element(msg)
+) -> App(flags, model, msg)
+```
+
+A `simple` program introduces the Model-View-Update architecture but leaves out
+the ability to dispatch side effects. This means your programs are interactive
+but cannot talk to the outside world.
+
+### application | javascript
+
+```gleam
+pub fn application(
+ init: fn(flags) -> #(model, Effect(msg)),
+ update: fn(model, msg) -> #(model, Effect(msg)),
+ view: fn(model) -> Element(msg)
+) -> App(flags, model, msg)
+```
+
+The `application` constructor is the most complete way to build a Lustre app. As
+with [`simple`](#simple) it uses the Model-View-Update architecture, but now your
+init and update functions can return side effects to be performed by the runtime
+in the form of an [`Effect`](/api/lustre/effect#effect-type).
+
+### start | javascript
+
+```gleam
+pub fn start(
+ app: App(flags, model, msg),
+ selector: String,
+ flags: flags,
+) -> Result(fn(msg) -> Nil, Error)
+```
+
+Start an application by providing a CSS selector to find the element to mount the
+application onto and any flags to pass to the application on first init. This
+function returns a `Result` and may fail for a number of reasons. Check out the
+[`Error`](#error-type) type for more information.
+
+### destroy | javascript
+
+```gleam
+pub fn destroy(app: App(flags, model, msg)) -> Result(Nil, Error)
+```
+
+Tear down a running application and remove it from the DOM. This can fail if the
+application has not yet been started.
+
+## Components
+
+Components take the same Model-View-Update building blocks used to create Lustre
+applications and allow them to be used as reusable stateful components. This is
+slightly different to how components are used in other frameworks like React
+where "component" refers more generally to any reusable piece of UI.
+
+In Lustre, functions that return an `Element` are known as "view functions" and
+components are more specific abstractions that encapsulate state and behaviour
+you might not want to deal with in your top-level application.
+
+Resist the urge to reach for components too early. The Elm community has managed
+to make do without components at all: you can get surprisingly far storing state
+in your top level application and passing it down to different view functions.
+This comes with the added benefit of it being much easier to reason about your
+UI as a whole.
+
+### component | javascript
+
+```gleam
+pub fn component(
+ name: String,
+ init: fn() -> #(model, Effect(msg)),
+ update: fn(model, msg) -> #(model, Effect(msg)),
+ view: fn(model) -> Element(msg),
+ on_attribute_change: Map(String, Decoder(msg)),
+) -> Result(Nil, Error)
+```
+
+Register a component with the runtime from the familiar Model-View-Update building
+blocks. Compared to an application, we have two additional arguments:
+
+- A name for the component. This name must follow the same rules laid out in the
+ [custom element spec](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name)
+ and should contain a hyphen (`-`) to avoid clashes with built-in HTML elements.
+- A map of attribute names to listen for changes to and a decoder for each to
+ decode those attributes into messages to send to your component's `update`
+ function.
+
+If it feels like the API for registering components is a little more verbose than
+you're used to, that's because it is! You can get surprisingly far storing state
+in your top level application and passing it down to different view functions
+without needing to use components at all. In fact, for communities like Elm this
+is the _only_ way to do things.
+
+## Utilities
+
+### is_browser | erlang javascript
+
+```gleam
+pub fn is_browser() -> Bool
+```
+
+Gleam has conditional compilation depending on whether you are targetting Erlang
+or JavaScript, but sometimes you want to be a bit more specific than that and
+check if you're running in the browser.
+
+This is a runtime check that will tell you just that. You could use this to create
+a view function that renders something simple on the backend but more complex or
+interactive on the frontend.
+
+### is_registered | erlang javascript
+
+```gleam
+pub fn is_registered(name: String) -> Bool
+```
+
+Lustre's components are built directly on the
+[custom element spec](https://html.spec.whatwg.org/multipage/custom-elements.html)
+which means they share the same global registery as other custom elements. This
+function can tell you if the name you want to use is already registered, by another
+Lustre component or otherwise.