Module

Bonsai.VirtualDom

Package
purescript-bonsai
Repository
grmble/purescript-bonsai

Purescript interface to Elm Virtual DOM

#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!

#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.

#Patch Source

newtype Patch msg

A Patch for efficient updates.

#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.

#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!"

#property Source

property :: forall a msg. 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.

#attribute Source

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

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

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.

#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.

#style Source

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

Specify a list of styles.

#on Source

on :: forall eff msg. String -> (CmdDecoder eff msg) -> Property msg

Create a custom event listener.

#onWithOptions Source

onWithOptions :: forall aff msg. String -> Options -> CmdDecoder aff msg -> Property msg

Same as on but you can set a few options.

#defaultOptions Source

defaultOptions :: Options

Everything is False by default.

defaultOptions =
    { stopPropagation = False
    , preventDefault = False
    }

#lazy Source

lazy :: forall a msg. (a -> VNode msg) -> a -> VNode msg

A performance optimization that delays the building of virtual DOM nodes.

Calling (view model) will definitely build some virtual DOM, perhaps a lot of it. Calling (lazy view model) delays the call until later. During diffing, we can check to see if model is referentially equal to the previous value used, and if so, we just stop. No need to build up the tree structure and diff it, we know if the input to view is the same, the output must be the same!

#lazy2 Source

lazy2 :: forall a b msg. (a -> b -> VNode msg) -> a -> b -> VNode msg

Same as lazy but checks on two arguments.

#lazy3 Source

lazy3 :: forall a b c msg. (a -> b -> c -> VNode msg) -> a -> b -> c -> VNode msg

Same as lazy but checks on three arguments.

#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.

#render Source

render :: forall aff msg. Document -> Emitter aff 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.

#diff Source

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

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

#applyPatches Source

applyPatches :: forall eff aff msg. Document -> Emitter aff msg -> Element -> VNode msg -> Patch msg -> Eff (bonsai :: BONSAI | 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.