helpers.gleam
1 //// Ergonomic helpers for Lightspeed components. 2 3 import lightspeed/agent/isa 4 import lightspeed/component 5 6 /// Construct a component from init/update/render functions. 7 pub fn make( 8 init init: fn() -> model, 9 update update: fn(model, msg) -> #(model, List(component.Command(msg))), 10 render render: fn(model) -> component.Rendered, 11 ) -> component.Component(model, msg) { 12 component.Component(init: init, update: update, render: render) 13 } 14 15 /// Render markup with an explicit fingerprint. 16 pub fn html_with_fingerprint( 17 markup: String, 18 fingerprint: String, 19 ) -> component.Rendered { 20 component.Rendered(html: markup, fingerprint: fingerprint) 21 } 22 23 /// Return an update result with no commands. 24 pub fn no_effect(model: model) -> #(model, List(component.Command(msg))) { 25 #(model, []) 26 } 27 28 /// Construct a dispatch command. 29 pub fn dispatch(msg: msg) -> component.Command(msg) { 30 component.Dispatch(msg) 31 } 32 33 /// Construct a pushed ISA instruction command. 34 pub fn push(instruction: isa.Instruction) -> component.Command(msg) { 35 component.Push(instruction) 36 } 37 38 /// Construct a navigate command. 39 pub fn navigate(to: String) -> component.Command(msg) { 40 push(isa.Navigate(to: to)) 41 } 42 43 /// Construct a patch command. 44 pub fn patch(target: String, html: String) -> component.Command(msg) { 45 push(isa.Patch(target: target, html: html)) 46 } 47 48 /// Construct a subscription command. 49 pub fn subscribe(topic: String) -> component.Command(msg) { 50 push(isa.Subscribe(topic: topic)) 51 } 52 53 /// Construct an unsubscription command. 54 pub fn unsubscribe(topic: String) -> component.Command(msg) { 55 push(isa.Unsubscribe(topic: topic)) 56 } 57 58 /// Construct a shutdown command. 59 pub fn shutdown(reason: String) -> component.Command(msg) { 60 push(isa.Shutdown(reason: reason)) 61 } 62 63 /// Map the message type inside a component command. 64 pub fn map_command( 65 command: component.Command(inner), 66 with: fn(inner) -> outer, 67 ) -> component.Command(outer) { 68 case command { 69 component.NoCommand -> component.NoCommand 70 component.Dispatch(inner) -> component.Dispatch(with(inner)) 71 component.Push(instruction) -> component.Push(instruction) 72 } 73 } 74 75 /// Map message type for a list of commands. 76 pub fn map_commands( 77 commands: List(component.Command(inner)), 78 with: fn(inner) -> outer, 79 ) -> List(component.Command(outer)) { 80 case commands { 81 [] -> [] 82 [command, ..rest] -> [ 83 map_command(command, with), 84 ..map_commands(rest, with) 85 ] 86 } 87 }