Module

Elmish

Re-exports from Elmish.Boot

#BootRecord

type BootRecord props = { hydrate :: String -> props -> Effect Unit, mount :: String -> props -> Effect Unit, renderToString :: props -> String }

Support for the most common case entry point - i.e. mounting an Elmish component (i.e. ComponentDef structure) to an HTML DOM element with a known ID, with support for server-side rendering.

The function boot returns what we call BootRecord - a record of three functions:

  • mount - takes HTML element ID and props¹, creates an instance of the component, and mounts it to the HTML element in question
  • hydrate - same as mount, but expects the HTML element to already contain pre-rendered HTML inside. See React docs for more on server-side rendering: https://reactjs.org/docs/react-dom.html#hydrate
  • renderToString - meant to be called on the server (e.g. by running the code under NodeJS) to perform the server-side render. Takes props¹ and returns a String containing the resulting HTML.

The idea is that the PureScript code would export such BootRecord for consumption by bootstrap JavaScript code in the page and/or server-side NodeJS code (which could be written in PureScript or not). For "plain React" scenario, the JavaScript code in the page would just call mount. For "server-side rendering", the server would first call renderToString and serve the HTML to the client, and then the client-side JavaScript code would call hydrate.


¹ "props" here is a parameter used to instantiate the component (see example below). It is recommended that this parameter is a JavaScript record (hence the name "props"), because it would likely need to be supplied by some bootstrap JavaScript code.


Example:

-- PureScript:
module Foo(bootRecord) where

type Props = { hello :: String, world :: Int }

component :: Props -> ComponentDef Aff Message State
component = ...

bootRecord :: BootRecord Props
bootRecord = boot component


// Server-side JavaScript NodeJS code
const foo = require('output/Foo/index.js')
const fooHtml = foo.bootRecord.renderToString({ hello: "Hi!", world: 42 })
serveToClient("<html><body><div id='foo'>" + fooHtml + "</div></body></html>")


// Client-side HTML + JS:
<html>
   <body>
     <div id='foo'>
       ... server-side-rendered HTML goes here
     </div>
   </body>
   <script src="foo_bundle.js" />
   <script>
     Foo.bootRecord.hydrate('foo', { hello: "Hi!", world: 42 })
   </script>
</html>

#boot

boot :: forall msg state props. (props -> ComponentDef Aff msg state) -> BootRecord props

Creates a boot record for the given component. See comments for BootRecord.

Re-exports from Elmish.Component

#Transition

data Transition m msg state

A UI component state transition: wraps the new state value together with a (possibly empty) list of effects that the transition has caused (called "commands"), with each command possibly producing some new messages.

Instances of this type may be created either by using the smart constructor:

update :: State -> Message -> Transition Aff Message State
update state m = transition state [someCommand]

or in monadic style (see comments on fork for more on this):

update :: State -> Message -> Transition Aff Message State
update state m = do
    s1 <- Child1.update state.child1 Child1.SomeMessage # lmap Child1Msg
    s2 <- Child2.modifyFoo state.child2 # lmap Child2Msg
    fork someEffect
    pure state { child1 = s1, child2 = s2 }

or, for simple sub-component delegation, the BiFunctor instance may be used:

update :: State -> Message -> Transition Aff Message State
update state (ChildMsg m) =
    Child.update state.child m
    # bimap ChildMsg (state { child = _ })

Constructors

Instances

#ComponentDef

type ComponentDef m msg state = { init :: Transition m msg state, update :: state -> msg -> Transition m msg state, view :: state -> Dispatch msg -> ReactElement }

Definition of a component according to The Elm Architecture. Consists of three functions - init, view, update, - that together describe the lifecycle of a component.

Type parameters:

  • m - a monad in which the effects produced by update and init functions run.
  • msg - component's message.
  • state - component's state.

#withTrace

withTrace :: forall m msg state. DebugWarning => ComponentDef m msg state -> ComponentDef m msg state

Wraps the given component, intercepts its update cycle, and traces (i.e. prints to dev console) every command and every state value (as JSON objects), plus timing of renders and state transitions.

#transition

transition :: forall m state msg. Bind m => MonadEffect m => state -> Array (m msg) -> Transition m msg state

Smart constructor for the Transition type. See comments there. This function takes the new (i.e. updated) state and an array of commands - i.e. effects producing messages - and constructs a Transition out of them

#rmap

rmap :: forall f a b c. Bifunctor f => (b -> c) -> f a b -> f a c

Map a function over the second type arguments of a Bifunctor.

#nat

nat :: forall m n msg state. (m ~> n) -> ComponentDef m msg state -> ComponentDef n msg state

Monad transformation applied to ComponentDef

#lmap

lmap :: forall f a b c. Bifunctor f => (a -> b) -> f a c -> f b c

Map a function over the first type argument of a Bifunctor.

#forks

forks :: forall m message. Command m message -> Transition m message Unit

Similar to fork (see comments there for detailed explanation), but the parameter is a function that takes a message-dispatching callback. This structure allows the command to produce zero or multiple messages, unlike fork, whose callback has to produce exactly one.

Example:

update :: State -> Message -> Transition Aff Message State
update state msg = do
    forks countTo10
    pure state

countTo10 :: Command Aff Message
countTo10 msgSink =
    for_ (1..10) \n ->
        delay $ Milliseconds 1000.0
        msgSink $ Count n

#forkVoid

forkVoid :: forall m message. m Unit -> Transition m message Unit

Similar to fork (see comments there for detailed explanation), but the effect doesn't produce any messages, it's a fire-and-forget sort of effect.

#forkMaybe

forkMaybe :: forall m message. MonadEffect m => m (Maybe message) -> Transition m message Unit

Similar to fork (see comments there for detailed explanation), but the effect may or may not produce a message, as modeled by returning Maybe.

#fork

fork :: forall m message. MonadEffect m => m message -> Transition m message Unit

Creates a Transition that contains the given command (i.e. a message-producing effect). This is intended to be used for "accumulating" effects while constructing a transition in imperative-ish style. When used as an action inside a do block, this function will have the effect of "adding the command to the list" to be executed. The name fork reflects the fact that the given effect will be executed asynchronously, after the update function returns.

In more precise terms, the following:

trs :: Transition m Message State
trs = do
    fork f
    fork g
    pure s

Is equivalent to this:

trs :: Transition m Message State
trs = transition s [f, g]

At first glance it may seem that it's shorter to just call the transition smart constructor, but monadic style comes in handy for composing the update out of smaller pieces. Here's a more full example:

data Message = ButtonClicked | OnNewItem String

update :: State -> Message -> Transition Aff Message State
update state ButtonClick = do
    fork $ insertItem "new list"
    incButtonClickCount state
update state (OnNewItem str) =
    ...

insertItem :: Aff Message
insertItem name = do
    delay $ Milliseconds 1000.0
    pure $ OnNewItem name

incButtonClickCount :: Transition Aff Message State
incButtonClickCount state = do
    forkVoid $ trackingEvent "Button click"
    pure $ state { buttonsClicked = state.buttonsClicked + 1 }

#construct

construct :: forall msg state. ComponentDef Aff msg state -> Effect ReactElement

Given a ComponentDef, binds that def to a freshly created React class, instantiates that class, and returns a rendering function. Note that the return type of this function is almost the same as that of ComponentDef::view - except for state. This is not a coincidence: it is done this way on purpose, so that the result of this call can be used to construct another ComponentDef.

Unlike wrapWithLocalState, this function uses the bullet-proof strategy of storing the component state in a dedicated mutable cell, but that happens at the expense of being effectful.

#bimap

bimap :: forall f a b c d. Bifunctor f => (a -> b) -> (c -> d) -> f a c -> f b d

Re-exports from Elmish.Dispatch

#EffectFn2

data EffectFn2 :: Type -> Type -> Type -> Type

Instances

#EffectFn1

data EffectFn1 :: Type -> Type -> Type

Instances

#Dispatch

type Dispatch msg = msg -> Effect Unit

A function that a view can use to report messages originating from JS/DOM.

#mkEffectFn2

mkEffectFn2 :: forall a b r. (a -> b -> Effect r) -> EffectFn2 a b r

#mkEffectFn1

mkEffectFn1 :: forall a r. (a -> Effect r) -> EffectFn1 a r

#handleMaybe

handleMaybe :: forall arg msg. Dispatch msg -> (arg -> Maybe msg) -> EffectFn1 arg Unit

Same as handle, but dispatches a message optionally. See comments on handle for an example.

#handle

handle :: forall arg msg. Dispatch msg -> (arg -> msg) -> EffectFn1 arg Unit

A convenience function to make construction of event handlers with arguments (i.e. EffectFn1) a bit shorter. The function takes a Dispatch and a mapping from the event argument to a message which the given Dispatch accepts, and it's also available in operator form.

The following example demonstrates expected usage of both handle (in its operator form <|) and handleMaybe (in its operator form <?|):

textarea
  { value: state.text
  , onChange: dispatch <?| \e -> TextChanged <$> eventTargetValue e
  , onMouseDown: dispatch <| \_ -> TextareaClicked
  }

  where
    eventTargetValue = readForeign >=> lookup "target" >=> readForeign >=> lookup "value"

#(<|)

Operator alias for Elmish.Dispatch.handle (right-associative / precedence 9)

#(<?|)

Operator alias for Elmish.Dispatch.handleMaybe (right-associative / precedence 9)

Re-exports from Elmish.JsCallback

#JsCallback0

type JsCallback0 = JsCallback (Effect Unit)

A parameterless JsCallback

#JsCallback

newtype JsCallback (fn :: Type)

This type represents a function that has been wrapped in a way suitable for passing to JavaScript (including parameter validation). The primary use case for such callbacks is to pass them to JSX code for receiving DOM-generated events and turning them into UI messages. See MkJsCallback for more info and examples.

Instances

#jsCallback

jsCallback :: forall fn. MkJsCallback fn => fn -> JsCallback fn

Wraps a given effect fn (possibly with parameters) as a JS non-curried function with parameter type validation, making it suitable for passing to unsafe JS code.

This function should not (or at least rarely) be used directly. In normal scenarios, Elmish.Dispatch.handle should be used instead.

Example:

  -- PureScript:
  createElement' ffiComponent_
      { onSave: jsCallback $ Console.log "Save"
      , onCancel: jsCallback $ Console.log "Cancel"
      , onFoo: jsCallback \(bar::String) (baz::Int) ->
          Console.log $ "bar = " <> bar <> ", baz = " <> show baz
      }

 // JSX:
 export const FfiComponent = props =>
   <div>
     <button onClick={props.onSave}>Save</button>
     <button onClick={props.onCancel}>Cancel</button>
     <button onClick={() => props.onFoo("bar", 42)}>Foo</button>
   </div>

In this example, the parameters bar and baz will undergo validation at runtime to make sure they are indeed a String and an Int respectively, and an error will be issued if validation fails.

Re-exports from Elmish.React

#ReactElement

data ReactElement :: Type

Instantiated subtree of React DOM. JSX syntax produces values of this type.

Instances

#ReactComponent

data ReactComponent :: Type -> Type

This type represents constructor of a React component with a particular behavior. The type prameter is the record of props (in React lingo) that this component expects. Such constructors can be "rendered" into ReactElement via createElement.

#createElement'

createElement' :: forall props. ValidReactProps props => ReactComponent props -> props -> ReactElement

Variant of createElement for creating an element without children.

#createElement

createElement :: forall props content. ValidReactProps props => ReactChildren content => ReactComponent props -> props -> content -> ReactElement

The PureScript import of the React’s createElement function. Takes a component constructor, a record of props, some children, and returns a React DOM element.

To represent HTML data- attributes, createElement supports the _data :: Object prop.

Example

import Elmish.HTML as H
import Foreign.Object as FO

H.div
  { _data: FO.fromHomogenous { toggle: "buttons } }
  [...]

represents the <div data-toggle="buttons"> DOM element.

Modules