Module

Bonsai

Package
purescript-bonsai
Repository
grmble/purescript-bonsai

Bonsai main module for imports

View code will also want Bonsai.Html and Bonsai.Event

Re-exports from Bonsai.Core

#UpdateResult Source

type UpdateResult model msg = { cmd :: Cmd msg, model :: model }

An update functions returns a new model and a possibly empty command

#ProgramState Source

type ProgramState model msg = { dnode :: Element, model :: model, vnode :: VNode msg }

ProgramState tracks the current state of the model, vnode and dom element.

These are needed to advance the state in reaction to a Cmd message.

#Program Source

type Program model msg = { dbgEvents :: Boolean, dbgTiming :: Boolean, pending :: Ref (Array msg), renderer :: model -> VNode msg, state :: Ref (ProgramState model msg), updater :: model -> msg -> UpdateResult model msg }

Program describes the Bonsai program.

It is passed around in a ReaderT and stores callbacks and a ref to the pending commands. Event callbacks append to the list of pending commands, they will then be applied in the main event loop.

#program Source

program :: forall msg model eff. Element -> (model -> msg -> UpdateResult model msg) -> (model -> VNode msg) -> model -> Eff (console :: CONSOLE, dom :: DOM, ref :: REF | eff) (Program model msg)

Create initial environment for the Bonsai program.

#plainResult Source

plainResult :: forall msg model. model -> UpdateResult model msg

Creates an update result with empty command.

#mapResult Source

mapResult :: forall msg2 model2 msg1 model1. (model1 -> model2) -> (msg1 -> msg2) -> UpdateResult model1 msg1 -> UpdateResult model2 msg2

Helper to map update results from sub-components

#debugProgram Source

debugProgram :: forall msg model eff. Element -> Boolean -> Boolean -> (model -> msg -> UpdateResult model msg) -> (model -> VNode msg) -> model -> Eff (console :: CONSOLE, dom :: DOM, ref :: REF | eff) (Program model msg)

Re-exports from Bonsai.DOM

#domElementById Source

domElementById :: forall eff. ElementId -> Eff (dom :: DOM | eff) (Maybe Element)

Gets a DOM Element by its ID

Re-exports from Bonsai.Types

#Cmd Source

data Cmd msg

A Command represents messages that should be applied to the Bonsai model

It is a functor so event results can be mapped.

Constructors

Instances

Re-exports from Bonsai.VirtualDom

#VNode Source

newtype VNode msg

An immutable chunk of data representing a DOM node. This can be HTML or SVG.

It's a functor that maps the Cmds that are emitted by event handlers.

Instances

#Property Source

newtype Property msg

When using HTML and JS, there are two ways to specify parts of a DOM node.

  1. Attributes — You can set things in HTML itself. So the class in <div class="greeting"></div> is called an attribute.

  2. Properties — You can also set things in JS. So the className in div.className = 'greeting' is called a property.

So the class attribute corresponds to the className property. At first glance, perhaps this distinction is defensible, but it gets much crazier. There is not always a one-to-one mapping between attributes and properties! Yes, that is a true fact. Sometimes an attribute exists, but there is no corresponding property. Sometimes changing an attribute does not change the underlying property. For example, as of this writing, the webkit-playsinline attribute can be used in HTML, but there is no corresponding property!

Instances

#Patch Source

newtype Patch msg

A Patch for efficient updates.

#Options Source

type Options = { preventDefault :: Boolean, stopPropagation :: Boolean }

Options for an event listener. If stopPropagation is true, it means the event stops traveling through the DOM so it will not trigger any other event listeners. If preventDefault is true, any built-in browser behavior related to the event is prevented. For example, this is used with touch events when you want to treat them as gestures of your own, not as scrolls.

#EventDecoder Source

type EventDecoder msg = Foreign -> F (Cmd msg)

A EventDecoder turns DOM events into messages.

#text Source

text :: forall msg. String -> VNode msg

Just put plain text in the DOM. It will escape the string so that it appears exactly as you specify.

text "Hello World!"

#style Source

style :: forall msg. Array (Tuple String String) -> Property msg

Specify a list of styles.

myStyle : Property msg
myStyle =
  style
    [ ("backgroundColor", "red")
    , ("height", "90px")
    , ("width", "100%")
    ]

greeting : Node msg
greeting =
  node "div" [ myStyle ] [ text "Hello!" ]

#render Source

render :: forall msg eff. Emitter eff msg -> VNode msg -> Element

Render a virtual dom node to a DOM Element.

Initial step - the whole point in a VDom is the diffing and patching. So after rendering once, diff and applyPatches should be used.

#property Source

property :: forall msg a. String -> a -> Property msg

Create arbitrary properties.

import JavaScript.Encode as Json

greeting : Html greeting = node "div" [ property "className" (Json.string "greeting") ] [ text "Hello!" ]

Notice that you must give the property name, so we use className as it would be in JavaScript, not class as it would appear in HTML.

#onWithOptions Source

onWithOptions :: forall msg. String -> Options -> EventDecoder msg -> Property msg

Same as on but you can set a few options.

#on Source

on :: forall msg. String -> (EventDecoder msg) -> Property msg

Create a custom event listener.

import Json.Decode as Json

onClick : msg -> Property msg
onClick msg =
  on "click" (Json.succeed msg)

You first specify the name of the event in the same format as with JavaScript’s addEventListener. Next you give a JSON decoder, which lets you pull information out of the event object. If the decoder succeeds, it will produce a message and route it to your update function.

#node Source

node :: forall msg. String -> Array (Property msg) -> Array (VNode msg) -> VNode msg

Create a DOM node with a tag name, a list of HTML properties that can include styles and event listeners, a list of CSS properties like color, and a list of child nodes.

import Json.Encode as Json

hello : Node msg hello = node "div" [] [ text "Hello!" ]

greeting : Node msg greeting = node "div" [ property "id" (Json.string "greeting") ] [ text "Hello!" ]

#keyedNode Source

keyedNode :: forall msg. String -> Array (Property msg) -> Array (Tuple String (VNode msg)) -> VNode msg

Works just like node, but you add a unique identifier to each child node. You want this when you have a list of nodes that is changing: adding nodes, removing nodes, etc. In these cases, the unique identifiers help make the DOM modifications more efficient.

#diff Source

diff :: forall msg. VNode msg -> VNode msg -> Patch msg

Compute a patch between the old vnode representation and the new one.

#attributeNS Source

attributeNS :: forall msg. String -> String -> String -> Property msg

Would you believe that there is another way to do this?! This corresponds to JavaScript's setAttributeNS function under the hood. It is doing pretty much the same thing as attribute but you are able to have "namespaced" attributes. This is used in some SVG stuff at least.

#attribute Source

attribute :: forall msg. String -> String -> Property msg

Create arbitrary HTML attributes. Maps onto JavaScript’s setAttribute function under the hood.

greeting : Html
greeting =
    node "div" [ attribute "class" "greeting" ] [
      text "Hello!"
    ]

Notice that you must give the attribute name, so we use class as it would be in HTML, not className as it would appear in JS.

#applyPatches Source

applyPatches :: forall msg eff. Emitter eff msg -> Element -> VNode msg -> Patch msg -> Eff (dom :: DOM | eff) Element

Apply a diff between VDoms to the DOM element.

The DOM element should be the one from the last diff/applyPatches pass, or the initially rendered one.