Elmish
- Package
- purescript-elmish
- Repository
- collegevine/purescript-elmish
Re-exports from Elmish.Boot
#BootResult Source
data BootResult
Possible results of mounting the app root to a DOM element
#boot' Source
boot' :: forall state msg. { def :: ComponentDef Aff msg state, domElementId :: String, onViewError :: DispatchError -> Effect Unit } -> Effect BootResult
Mounts the given UI component to a DOM element with given ID
#boot Source
boot :: forall state msg. { def :: ComponentDef Aff msg state, domElementId :: String } -> Effect Unit
Mounts the given UI component to a DOM element with given ID. If the DOM
element with given ID doesn't exist, logs to console and returns normally.
For a more sophisticated handling of this case, use boot'
.
Re-exports from Elmish.Component
#Transition Source
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, with each effect ultimately producing a new message.
Constructors
Transition state (Array (m msg))
Instances
(Functor m) => Bifunctor (Transition m)
Functor (Transition m msg)
Apply (Transition m msg)
Applicative (Transition m msg)
#ComponentDef Source
type ComponentDef m msg state = { init :: Transition m msg state, update :: state -> msg -> Transition m msg state, view :: state -> DispatchMsgFn 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 byupdate
andinit
functions run.msg
- component's message.state
- component's state.
#withTrace Source
withTrace :: forall state msg m. 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).
#pureUpdate Source
pureUpdate :: forall state msg m. state -> Transition m msg state
Creates a Transition
without any commands.
This function will be deprecated soon in favor of pure
.
#nat Source
nat :: forall state msg n m. (forall a. m a -> n a) -> ComponentDef m msg state -> ComponentDef n msg state
Monad transformation applied to ComponentDef
#construct Source
construct :: forall state msg. ComponentDef Aff msg state -> Effect (DispatchMsgFn Unit -> 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.
#(<$$>) Source
Operator alias for Elmish.Component.mapCmds (non-associative / precedence 8)
A nested map
- useful for mapping over commands in an array: first map
maps over the array, second map
maps over the monad m
.
Example:
let (Transition subS cmds) = SubComponent.update s.subComponent msg
in Transition (s { subComponent = subS }) (SubComponentMsg <$$> cmds)
Re-exports from Elmish.Dispatch
#DispatchMsgFn Source
newtype DispatchMsgFn msg
Represents a function that a view can use to report both errors and
messages originating from JS/DOM. Underneath it's just a function that
takes an Either
, but it is wrapped in a newtype in order to provide class
instances for it.
Constructors
DispatchMsgFn (Either DispatchError msg -> Effect Unit)
Instances
#DispatchMsg Source
type DispatchMsg = Effect Unit
#DispatchError Source
type DispatchError = String
#handleMaybe Source
handleMaybe :: forall effFn fn msg. MkEventHandler (Maybe msg) fn effFn => MkJsCallback effFn => DispatchMsgFn msg -> fn -> JsCallback effFn
A version of handle
(see comments there) with a possibility of not
producing a message.
#handle Source
handle :: forall effFn fn msg. MkEventHandler msg fn effFn => MkJsCallback effFn => DispatchMsgFn msg -> fn -> JsCallback effFn
Creates a JsCallback
that uses the given DispatchMsgFn
to either issue
a message or report an error. The fn
parameter is either a message or a
function that produces a message. When the JS code calls the resulting
JsCallback
, its parameters are validated, then the fn
function is
called to produce a message, which is then reported via the given
DispatchMsgFn
, unless the parameters passed from JS cannot be decoded, in
which case an error is reported via DispatchMsgFn
.
Example of intended usage:
-- PureScript
data Message = A | B Int | C String Boolean
view state dispatch = createElement' viewCtor_
{ foo: "bar"
, onA: handle dispatch A
, onB: handle dispatch B
, onC: handle dispatch C
, onBaz: handle dispatch \x y -> B (x+y)
}
// JSX:
export const viewCtor_ = args =>
<div>
Foo is {args.bar}<br />
<button onClick={args.onA}>A</button>
<button onClick={() => args.onB(42)}>B</button>
<button onClick={() => args.onC("hello", true)}>C</button>
<button onClick={() => args.onBaz(21, 21)}>Baz</button>
</div>
Re-exports from Elmish.JsCallback
#JsCallback0 Source
type JsCallback0 = JsCallback (Effect Unit)
A parameterless JsCallback
#JsCallback Source
newtype JsCallback fn
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
(MkJsCallback fn) => CanPassToJavaScript (JsCallback fn)
#mkJsCallback Source
mkJsCallback :: forall fn. MkJsCallback fn => fn -> (JsCallbackError -> Effect Unit) -> 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' theView_
{ onSave: jsCallback0 $ Console.log "Save"
, onCancel: jsCallback0 $ Console.log "Cancel"
, onFoo: mkJsCallback
(\(bar::Int) (baz::Int) ->
Console.log $ "bar = " <> show bar <> ", baz = " <> show baz
)
(\err -> pure unit {- ignore errors -})
}
// JSX:
export const TheView = props =>
<div>
<button onClick={props.onSave}>Save</button>
<button onClick={props.onCancel}>Cancel</button>
<button onClick={() => props.onFoo("bar", "baz")}>Foo</button>
</div>
In this example, the parameters bar
and baz
will undergo validation at
runtime, and an error will be issued if validation fails.
#jsCallback0 Source
jsCallback0 :: Effect Unit -> JsCallback0
A wrapper for mkJsCallback
(see comments there)
Re-exports from Elmish.React
#ReactElement Source
data ReactElement :: Type
Instantiated subtree of React DOM. JSX syntax produces values of this type.
Instances
#ReactComponent Source
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' Source
createElement' :: forall props. ValidReactProps props => ReactComponent props -> props -> ReactElement
Variant of createElement
for creating an element without children.
#createElement Source
createElement :: forall content props. 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.
Re-exports from Elmish.Ref
#Ref Source
newtype Ref (name :: Symbol) a
An opaque reference for tunneling through JSX code.
This type is a wrapper that lets us pass any PureScript values into JSX
code, with the expectation that the JSX code cannot mess with (inspect,
mutate) these values, but can pass them back to the PureScript code in
messages. This type has instances of CanPassToJavaScript
and
CanReceiveFromJavaScript
, which allows it to be passed in React props or
view messages.
One challenge with this type is that we can't just unsafeCoerce
its
values back and forth, because that would open a very big hole for data
corruption to get in. To have some protection against it, we add a weak
form of verification: internally values of Ref
are represented by a
JavaScript hash with a sole key looking like "ref:name", whose value is the
target of the ref, and where "name" is the first type argument of this
Ref
. This way, we have at least something to verify (see the
CanReceiveFromJavaScript
instance below) that the object passed by the
JSX code is not some random value, but actually originated as a Ref a
of
the right type.
Admittedly, this is only weak protection, because the JSX code can still,
if it really wanted to, construct a hash like { "ref:name": "abracadabra"}
and pass it to the PureScript code, which would happily
accept the "abracadabra" value as if it was the right type.
Here are my arguments for why this weak protection is enough:
- The JSX code has to actually try to be destructive. Can't happen by accident.
- It's technically impossible to do any better without putting
significant restrictions on the type
a
(i.e. requiring it to beGeneric
or to provide type name, etc.), and without losing some performance. - If such corruption proves to be a problem in the future, we can always
fall back to encoding/decoding
Json
, and pay some performance for it.
Instances
(IsSymbol name) => CanReceiveFromJavaScript (Ref name a)
(IsSymbol name) => CanPassToJavaScript (Ref name a)