diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2024-01-27 02:25:30 +0000 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2024-01-27 02:25:30 +0000 |
commit | e8a3fb4e62415fef7e2d70e6911f5c018409761c (patch) | |
tree | 1809f84aa4e0be1148d1e2cd188948b90b441bb0 /src/lustre.gleam | |
parent | c34d1a0e9003d483752720466def696c30f705c8 (diff) | |
download | lustre-e8a3fb4e62415fef7e2d70e6911f5c018409761c.tar.gz lustre-e8a3fb4e62415fef7e2d70e6911f5c018409761c.zip |
:art: Strip whitespace because Zed said so.
Diffstat (limited to 'src/lustre.gleam')
-rw-r--r-- | src/lustre.gleam | 120 |
1 files changed, 59 insertions, 61 deletions
diff --git a/src/lustre.gleam b/src/lustre.gleam index 77c86cf..77e0bb5 100644 --- a/src/lustre.gleam +++ b/src/lustre.gleam @@ -1,46 +1,46 @@ //// Lustre is a framework for rendering Web applications and components using //// Gleam. This module contains the core API for constructing and communicating //// with the different kinds of Lustre application. -//// +//// //// Lustre currently has two kinds of application: -//// +//// //// 1. A client-side single-page application: think Elm or React or Vue. These //// are applications that run in the client's browser and are responsible for //// rendering the entire page. -//// +//// //// 2. A client-side component: an encapsulated Lustre application that can be //// rendered inside another Lustre application as a Web Component. Communication //// happens via attributes and event listeners, like any other encapsulated //// HTML element. -//// +//// //// 3. A Lustre Server Component. These are applications that run anywhere Gleam //// runs and communicate with any number of connected clients by sending them -//// patches to apply to their DOM. -//// +//// patches to apply to their DOM. +//// //// On the server, these applications can be communicated with by sending them //// messages directly. On the client communication happens the same way as //// client-side components: through attributes and event listeners. -//// +//// //// No matter where a Lustre application runs, it will always follow the same //// Model-View-Update architecture. Popularised by Elm (where it is known as The //// Elm Architecture), this pattern has since made its way into many other //// languages and frameworks and has proven to be a robust and reliable way to //// build complex user interfaces. -//// +//// //// There are three main building blocks to the Model-View-Update architecture: -//// +//// //// - A `Model` that represents your application's state and an `init` function //// to create it. -//// +//// //// - A `Msg` type that represents all the different ways the outside world can //// communicate with your application and an `update` function that modifies //// your model in response to those messages. -//// +//// //// - A `view` function that renders your model to HTML, represented as an //// `Element`. -//// +//// //// To see how those pieces fit together, here's a little diagram: -//// +//// //// ```text //// +--------+ //// | | @@ -68,14 +68,14 @@ //// | | //// +--------+ //// ``` -//// +//// //// ❓ Wondering what that [`Effect`](./effect#effect-type) is all about? Check //// out the documentation for that over in the [`effect`](./effect) module. -//// +//// //// For many kinds of app, you can take these three building blocks and put //// together a Lustre application capable of running *anywhere*. We like to -//// describe Lustre as a **universal framework**. -//// +//// describe Lustre as a **universal framework**. +//// //// To read the full documentation for this module, please visit //// [https://lustre.build/api/lustre](https://lustre.build/api/lustre) @@ -94,23 +94,23 @@ import lustre/runtime // TYPES ----------------------------------------------------------------------- /// Represents a constructed Lustre application that is ready to be started. -/// Depending on the kind of application you've constructed you have a few +/// Depending on the kind of application you've constructed you have a few /// options: -/// +/// /// - Use [`start`](#start) to start a single-page-application in the browser. -/// +/// /// - Use [`start_server_component`](#start_server_component) to start a Lustre /// Server Component anywhere Gleam will run: Erlang, Node, Deno, or in the /// browser. -/// +/// /// - Use [`start_actor`](#start_actor) to start a Lustre Server Component only /// for the Erlang target. BEAM users should always prefer this over /// `start_server_component` so they can take advantage of OTP features. -/// +/// /// - Use [`register`](#register) to register a component in the browser to be /// used as a Custom Element. This is useful even if you're not using Lustre /// to build a SPA. -/// +/// pub opaque type App(flags, model, msg) { App( init: fn(flags) -> #(model, Effect(msg)), @@ -122,37 +122,34 @@ pub opaque type App(flags, model, msg) { /// The `Browser` runtime is the most typical kind of Lustre application: it's /// a single-page application that runs in the browser similar to React or Vue. -/// +/// pub type ClientSpa /// A `ServerComponent` is a type of Lustre application that does not directly -/// render anything to the DOM. Instead, it can run anywhere Gleam runs and +/// render anything to the DOM. Instead, it can run anywhere Gleam runs and /// operates in a "headless" mode where it computes diffs between renders and /// sends them to any number of connected listeners. -/// +/// /// Lustre Server Components are not tied to any particular transport or network /// protocol, but they are most commonly used with WebSockets in a fashion similar /// to Phoenix LiveView. -/// +/// pub type ServerComponent /// An action represents a message that can be sent to (some types of) a running /// Lustre application. Like the [`App`](#App) type, the `runtime` type parameter /// can be used to determine what kinds of application a particular action can be /// sent to. -/// -/// -/// +/// +/// +/// pub type Action(runtime, msg) = runtime.Action(runtime, msg) /// Starting a Lustre application might fail for a number of reasons. This error /// type enumerates all those reasons, even though some of them are only possible /// on certain targets. -/// -/// This generally makes error handling simpler than having to worry about a bunch -/// of different error types and potentially unifying them yourself. -/// +/// pub type Error { ActorError(StartError) BadComponentName(name: String) @@ -168,14 +165,14 @@ pub type Error { /// once and does not handle any messages or effects. Often this type of application /// is used for folks just getting started with Lustre on the frontend and want a /// quick way to get something on the screen. -/// +/// /// Take a look at the [`simple`](#simple) application constructor if you want to /// build something interactive. -/// +/// /// 💡 Just because an element doesn't have its own update loop, doesn't mean its /// content is always static! An element application may render a component or /// server component that has its own encapsulated update loop! -/// +/// pub fn element(html: Element(msg)) -> App(Nil, Nil, msg) { let init = fn(_) { #(Nil, effect.none()) } let update = fn(_, _) { #(Nil, effect.none()) } @@ -185,7 +182,7 @@ pub fn element(html: Element(msg)) -> App(Nil, Nil, msg) { } /// -/// +/// pub fn simple( init: fn(flags) -> model, update: fn(model, msg) -> model, @@ -198,7 +195,7 @@ pub fn simple( } /// -/// +/// pub fn application( init: fn(flags) -> #(model, Effect(msg)), update: fn(model, msg) -> #(model, Effect(msg)), @@ -208,7 +205,7 @@ pub fn application( } /// -/// +/// pub fn component( init: fn(flags) -> #(model, Effect(msg)), update: fn(model, msg) -> #(model, Effect(msg)), @@ -221,7 +218,7 @@ pub fn component( // EFFECTS --------------------------------------------------------------------- /// -/// +/// pub fn start( app: App(flags, model, msg), onto selector: String, @@ -232,10 +229,11 @@ pub fn start( } @external(javascript, "./client-runtime.ffi.mjs", "start") -fn do_start(_app: App(flags, model, msg), _selector: String, _flags: flags) -> Result( - fn(Action(ClientSpa, msg)) -> Nil, - Error, -) { +fn do_start( + _app: App(flags, model, msg), + _selector: String, + _flags: flags, +) -> Result(fn(Action(ClientSpa, msg)) -> Nil, Error) { // It should never be possible for the body of this function to execute on the // Erlang target because the `is_browser` guard will prevent it. Instead of // a panic, we still return a well-typed `Error` here in the case where someone @@ -246,21 +244,21 @@ fn do_start(_app: App(flags, model, msg), _selector: String, _flags: flags) -> R /// /// @external(javascript, "./server-runtime.ffi.mjs", "start") -pub fn start_server_component(app: App(flags, model, msg), with flags: flags) -> Result( - fn(Action(ServerComponent, msg)) -> Nil, - Error, -) { +pub fn start_server_component( + app: App(flags, model, msg), + with flags: flags, +) -> Result(fn(Action(ServerComponent, msg)) -> Nil, Error) { use runtime <- result.map(start_actor(app, flags)) actor.send(runtime, _) } /// -/// +/// /// 🚨 This function is only meaningful on the Erlang target. Attempts to call /// it on the JavaScript will result in the `NotErlang` error. If you're running -/// a Lustre Server Component on Node or Deno, use +/// a Lustre Server Component on Node or Deno, use /// [`start_server_component`](#start_server_component) instead. -/// +/// pub fn start_actor( app: App(flags, model, msg), with flags: flags, @@ -286,19 +284,19 @@ fn do_start_actor( /// Register a Lustre application as a Web Component. This lets you render that /// application in another Lustre application's view or use it as a Custom Element /// outside of Lustre entirely. -/// +/// /// 💡 The provided application can only have `Nil` flags, because there is no way /// to specify flags when the component is first rendered. -/// +/// /// 💡 There are [some rules](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names) /// for what names are valid for a Custom Element. The most important one is that /// the name *must* contain a hypen so that it can be distinguished from standard /// HTML elements. -/// +/// /// 🚨 This function is only meaningful when running in the browser. For server /// contexts, you can render a Lustre Server Component using `start_server_component` /// or `start_actor` instead. -/// +/// @external(javascript, "./client-component.ffi.mjs", "register") pub fn register(app: App(Nil, model, msg), name: String) -> Result(Nil, Error) { Error(NotABrowser) @@ -333,12 +331,12 @@ pub fn shutdown() -> Action(runtime, msg) { /// Gleam's conditional compilation makes it possible to have different implementations /// of a function for different targets, but it's not possible to know what runtime -/// you're targetting at compile-time. -/// +/// you're targetting at compile-time. +/// /// This is problematic if you're using Lustre Server Components with a JavaScript /// backend because you'll want to know whether you're currently running on your -/// server or in the browser: this function tells you that! -/// +/// server or in the browser: this function tells you that! +/// @external(javascript, "./client-runtime.ffi.mjs", "is_browser") pub fn is_browser() -> Bool { False @@ -347,7 +345,7 @@ pub fn is_browser() -> Bool { /// Check if the given component name has already been registered as a Custom /// Element. This is particularly useful in contexts where _other web components_ /// may have been registered and you must avoid collisions. -/// +/// @external(javascript, "./client-runtime.ffi.mjs", "is_registered") pub fn is_registered(name: String) -> Bool { False |