All the code snippets on this page are live and interactive powered by the klipse plugin.
A collection of utilities for working with Karet.
U.changes(observable) ⌘U.debounce(ms, observable) ⌘U.delay(ms, observable) ⌘U.flatMapErrors(value => observable, observable) ⌘U.flatMapLatest(value => observable, observable) ⌘U.flatMapParallel(value => observable, observable) ⌘U.flatMapSerial(value => observable, observable) ⌘U.foldPast((state, value) => state, state, observable) ⌘U.fromEvents(target, eventName, transform) ⌘U.ignoreErrors(observable) ⌘U.ignoreValues(observable) ⌘U.interval(ms, value) ⌘U.later(ms, value) ⌘U.mapValue(value => value, observable) ⌘U.never ⌘U.parallel([...observables]) ⌘U.sampledBy(eventStream, property) ⌘U.serially([...observables]) ⌘U.skipDuplicates(equality, observable) ⌘U.skipFirst(number, observable) ⌘U.skipFirstErrors(n, observable) ⌘U.skipUnless(predicate, observable) ⌘U.takeFirst(number, observable) ⌘U.takeFirstErrors(number, observable) ⌘U.takeUntilBy(eventStream, observable) ⌘U.throttle(ms, observable) ⌘U.toObservable(observable) ⌘U.toProperty(observable) ⌘U.abs(x) ⌘U.acos(x) ⌘U.acosh(x) ⌘U.asin(x) ⌘U.asinh(x) ⌘U.atan(x) ⌘U.atanh(x) ⌘U.atan2(y, x) ⌘U.cbrt(x) ⌘U.ceil(x) ⌘U.clz32(x) ⌘U.cos(x) ⌘U.cosh(x) ⌘U.exp(x) ⌘U.expm1(x) ⌘U.floor(x) ⌘U.fround(x) ⌘U.hypot(...xs) ⌘U.imul(x, y) ⌘U.log(x) ⌘U.log1p(x) ⌘U.log10(x) ⌘U.log2(x) ⌘U.max(...xs) ⌘U.min(...xs) ⌘U.pow(x, y) ⌘U.round(x) ⌘U.sign(x) ⌘U.sin(x) ⌘U.sinh(x) ⌘U.sqrt(x) ⌘U.tan(x) ⌘U.tanh(x) ⌘U.trunc(x) ⌘This library provides a large number of named exports. Typically one just imports the library as:
import * as U from 'karet.util'
Many of the functions in this library are lifted so that they accept both ordinary values and observables as inputs. When such functions are given only ordinary values as inputs, they return immediately with the result value. OTOH, when such a function is given at least an observable as an input, they return an observable of results.
U.show(...labels, any)U.show is basically an identity function that console.logs the values
flowing through. U.show works on plain values, observables, and atoms. When
used with atoms, U.show also logs values written through.
For example:
var Component = ({state}) => (
<div>
<SubComponent subState={U.show('subState', U.view('subState', state))}/>
</div>
)
U.atom(value)U.atom creates a new atom with the given initial value.
For example:
var notEmpty = U.atom('initial')
notEmpty.get() // 'initial'
notEmpty.log() // [property] <value:current> initial
U.molecule([ ... ] | { ... })U.molecule composes an atom from a template of atoms.
For example:
var xyA = U.atom({x: 1, y: 2})
var xL = U.view('x', xyA)
var yL = U.view('y', xyA)
var xyM = U.molecule({x: xL, y: yL})
When read, either as a property or via get, the atoms in the template are
replaced by their values:
R.equals( xyM.get(), xyA.get() ) // true
When written to, the atoms in the template are written to with matching elements from the written value:
xyM.modify(L.set('x', 3))
xL.get() // 3
yL.get() // 2
The writes are performed holding event propagation.
It is considered an error, and the effect is unpredictable, if the written value
does not match the template, aside from the positions of abstract mutables, of
course, which means that write operations, set, remove, and modify, on
molecules and lensed atoms created from molecules are only partial.
Also, if the template contains multiple abstract mutables that correspond to the same underlying state, then writing through the template will give unpredictable results.
U.variable()U.variable creates a new atom without an initial value. See also
U.refTo.
For example:
var empty = U.variable()
empty.get() // undefined
empty.log()
empty.set('first') // [property] <value> first
U.holding(() => { ... })U.holding is given a thunk to call while holding the propagation of events
from changes to atoms. The thunk can get, set, remove and modify any
number of atoms. After the thunk returns, persisting changes to atoms are
propagated. See also U.actions and U.getProps.
For example:
var xy = U.atom({x: 1, y: 2})
var x = U.view('x', xy)
var y = U.view('y', xy)
x.log('x') // x <value:current> 1
y.log('y') // y <value:current> 2
U.holding(() => {
xy.set({x: 2, y: 1})
x.set(x.get() - 1)
}) // y <value> 1
U.destructure(atom)U.destructure wraps a given atom or observable with a
proxy
that performs property access via U.view. On plain observable
properties only get access is supported. On mutable atoms get, set, and
deleteProperty accesses are supported.
For example,
var {name, number} = U.destructure(contact)
is equivalent to
var name = U.view('name', contact)
var number = U.view('number', contact)
Note that all property accesses through the proxy returned by U.destructure
are performed via U.view. This means that the return value of
U.destructure cannot be used as the atom or observable that it proxies.
Note that U.destructure is not recursive, which means that nested
destructuring cannot be used. Only single level property access is proxied.
Note that U.destructure requires proper
Proxy
support. You need to decide whether you can use
it.
U.mapElems((elemAtom, index) => any, arrayAtom)U.mapElems performs a cached incremental map over state containing an array of
values. On changes, the mapping function is only called for elements that were
not in the state previously. U.mapElems can be used for rendering a list of
stateless components, however, if elements in the array have unique ids, then
U.mapElemsWithIds is generally preferable.
For example:
var Contacts = ({contacts}) => (
<div>
{U.mapElems((contact, i) => <Contact {...{key: i, contact}} />, contacts)}
</div>
)
See the live Contacts CodeSandbox for an example.
U.mapElemsWithIds(idLens, (elemAtom, id) => any, arrayAtom)U.mapElemsWithIds performs a cached incremental map over state containing an
array of values with unique ids. On changes, the mapping function is only
called for elements that were not in the state previously. U.mapElemsWithIds
is particularly designed for rendering a list of potentially stateful
components efficiently. See also U.mapElems.
For example:
var state = U.atom([
{id: 1, value: 'Keep'},
{id: 2, value: 'Calmm'},
{id: 3, value: 'and'},
{id: 4, value: 'React!'}
])
var Elems = ({elems}) => (
<ul>
{U.mapElemsWithIds(
'id',
(elem, id) => <li key={id}>{U.view('value', elem)}</li>,
elems
)}
</ul>
)
U.mapElemsWithIds is asymptotically optimal in the sense that any change (new
elements added or old elements removed, positions of elements changed, ...) has
Theta(n) complexity. That is the best that can be achieved with plain arrays.
U.view(lens, atom)U.view creates a read-write view with the given lens from the given original
atom. The lens may also be an observable producing lenses. Modifications to
the lensed atom are reflected in the original atom and vice verse.
For example:
var root = U.atom({x: 1})
var x = U.view('x', root)
x.set(2)
root.get() // { x: 2 }
root.set({x: 3})
x.get() // 3
One of the key ideas that makes lensed atoms work is the compositionality of
partial lenses. Those
equations make it possible not just to create lenses via composition (left hand
sides of equations), but also to create paths of lensed atoms (right hand sides
of equations). More concretely, both the c in
var b = U.view(a_to_b_PLens, a)
var c = U.view(b_to_c_PLens, b)
and in
var c = U.view([a_to_b_PLens, b_to_c_PLens], a)
can be considered equivalent thanks to the compositionality equations of lenses.
Note that, for most intents and purposes, U.view is a referentially
transparent function:
it does not create new mutable state—it merely creates a reference to
existing mutable state.
U.view is the primary means of decomposing state for sub-components. For
example:
var Contact = ({contact}) => (
<div>
<TextInput value={U.view('name', contact)} />
<TextInput value={U.view('phone', contact)} />
</div>
)
See the live Contacts CodeSandbox for an example.
U.set(atom, value)U.set sets the given value to the specified atom. In case the value is
actually an observable, U.set returns a sink that sets any values
produced by the observable to the atom.
For example:
var Component = ({parameters}) => {
const state = U.atom(null)
// ...
return (
<div>
{U.set(state, httpRequestAsObservable(parameters))}
{U.ifElse(
R.isNil(state),
<Spinner />,
<Editor state={state} />
)}
</div>
)
}
Note that the above kind of arrangement to fetch data and set it into an atom is not needed when the data is only displayed in a read-only fashion in the UI.
U.doModify(atom, mapper)U.doModify creates an action that invokes the modify method on the given
atom with the given mapping function.
U.doRemove(atom)U.doRemove creates an action that invokes the remove method on the given
atom.
U.doSet(atom, value)U.doSet creates an action that invokes the set method on the given atom with
the given value.
U.bus()U.bus() creates a new observable Bus stream. A Bus stream has the
following methods:
bus.push(value) to explicitly emit value value,bus.error(error) to explicitly emit error error, andbus.end() to explicitly end the stream after which all the methods do
nothing.Note that buses and event streams, in general, are fairly rarely used with Karet. They can be useful for performing IO actions and in cases where actions from UI controls need to be throttled or combined.
See the live Counter using Event Streams CodeSandbox for an example.
U.serializer(initial[, [...actions]])U.serializer creates a new observable property for serially executing
actions, which are zero argument functions that may return a value or an
observable that should eventually end. The returned property starts with the
given initial value and then continues with the results of the optional array
of actions. Like a Bus, the returned property also has the
following extra methods:
bus.push(action) to explicitly push a new action to be executed,bus.error(error) to explicitly emit error error, andbus.end() to explicitly stop the serializer after which all the methods do
nothing.The property must be subscribed to in order to process actions.
See the Form using Context CodeSandbox for a minimalist example that uses a serializer to execute a simulated asynchronous operation.
U.doEnd(bus)U.doEnd creates an action that invokes the end method on the given bus.
U.doError(bus, error)U.doError creates an action that invokes the error method on the given bus
with the given value.
U.doPush(bus, value)U.doPush creates an action that invokes the push method on the given bus
with the given value.
U.scope((...) => ...)U.scope simply calls the given thunk. IOW, U.scope(fn) is equivalent to
(fn)(). You can use it to create a new scope at expression level.
For example:
U.scope((x = 1, y = 2) => x + y)
U.tapPartial(action, any)U.tapPartial is a lifted partial
tap function. The given action is called for
values flowing through except when the value is undefined.
For example:
U.thru(
observable,
...
U.tapPartial(value => console.log(value)),
...
)
U.thru(any, ...fns)U.thru allows one to pipe a value through a sequence of functions. In other
words, U.thru(x, fn_1, ..., fn_N) is roughly equivalent to fn_N( ... fn_1(x)
... ). It serves a similar purpose as the
->> macro of Clojure or the
|> operator of
F#
and Elm,
for example, or the
>|
operator defined in a Usenet post by some rando. See also
U.through.
For example:
U.thru(1, x => x + 1, x => -x)
A common technique in JavaScript is to use method chaining: x.fn_1().fn_2().
A problem with method chaining is that it requires having objects with methods.
Sometimes you may need to manipulate values that are not objects, like null
and undefined, and other times you may want to use functions that are not
directly provided as methods and it may not be desirable to monkey
patch such methods.
U.thru is designed to work with partially applied
curried and lifted
functions that take the object as their last
argument and can be seen as providing a flexible alternative to method chaining.
U.through(...fns)U.through allows one to compose a function that passes its single argument
through all of the given functions from left to right. In other words,
U.through(fn_1, ..., fn_N)(x) is roughly equivalent to fn_N( ... fn_1(x)
... ). It serves a similar purpose as
R.pipe, but has been crafted to work with
lifted functions. See also U.thru.
For example:
U.through(x => x + 1, x => -x)(1)
U.toPartial(fn)U.toPartial takes the given function and returns a curried version of the
function that immediately returns undefined if any of the arguments passed is
undefined and otherwise calls the given function with arguments.
For example:
U.toPartial((x, y) => x + y)(1, undefined)
U.toPartial((x, y) => x + y)(1, 2)
U.getProps({...propName: atom|bus})U.getProps returns an event callback that gets the values of the properties
named in the given template from the event target and pushes or sets them to the
buses or atoms that are the values of the properties. In case
the template contains multiple properties, the results are written while
holding change propagation.
For example:
var TextInput = ({value}) => (
<input type="text" value={value} onChange={U.getProps({value})} />
)
var Checkbox = ({checked}) => (
<input type="checkbox" checked={checked} onChange={U.getProps({checked})} />
)
U.setProps({...propName: observable})U.setProps returns a callback designed to be used with ref that subscribes
to observables in the given template and copies values from the observables to
the named properties in the DOM element. This allows one to bind to DOM
properties such as scroll position that are not HTML attributes. See also
U.actions.
See the live Scroll CodeSandbox for an example.
<U.Input {...{value|checked}} />U.Input is a wrapper for an input element that binds either
onChange={U.getProps({value})} or
onChange={U.getProps({checked})} when either value or
checked is a defined property.
For example:
var checked = U.atom(false)
// ...
<U.Input type="checkbox" checked={checked} />
<U.Select {...{value}} />U.Select is a wrapper for a select element that binds
onChange={U.getProps({value})} when value is a defined
property.
For example:
var value = U.atom('')
// ...
<U.Select value={value} />
<U.TextArea {...{value}} />U.TextArea is a wrapper for a textarea element that binds
onChange={U.getProps({value})} when value is a defined
property.
For example:
var value = U.atom('')
// ...
<U.TextArea value={value} />
U.refTo(variable)U.refTo is designed for getting a reference to the DOM element of a component.
See also U.variable. See also U.actions.
For example:
var Component = ({dom = U.variable()}) => (
<div ref={U.refTo(dom)}>
...
</div>
)
React calls the
ref callback with the DOM element on mount and with null on unmount.
However, U.refTo does not write null to the variable. The upside of
skipping null and using an initially empty variable rather than
an atom is that once the variable emits a value, you can be sure that
it refers to a DOM element.
Note that in case you also want to observe null values, you can use
U.set instead of U.refTo:
var Component = ({dom = U.variable()}) => (
<div ref={U.set(dom)}>
...
</div>
)
U.onUnmount(action)U.onUnmount allows you to perform an action when a component is unmounted.
For example:
var Component = () => {
console.log('Mounted!')
return (
<div>
{U.onUnmount(() => console.log('Unmounted!'))}
</div>
)
}
U.actions(...actions)U.actions is designed for creating an action from multiple actions. It
returns an unary action function that calls the functions in the arguments with
the same argument. In case there are multiple actions, they are performed while
holding change propagation.
For example:
var InputValue = ({value, onChange}) => (
<input value={value} onChange={U.actions(onChange, U.getProps({value}))} />
)
Note that in case onChange is not given to the above component as a property
it causes no problem as U.actions does not attempt to call undefined.
Note that U.actions can also be used with actions given to the React ref
property.
U.preventDefault(event)U.preventDefault invokes the preventDefault method on the given object.
U.stopPropagation(event)U.stopPropagation invokes the stopPropagation method on the given object.
U.cns(...classNames)U.cns is designed for creating a list of class names for the className
property. It joins the truthy values from the arguments with a space. In case
the result would be an empty string, undefined is returned instead.
For example:
var Component = ({className}) => (
<div className={U.cns(className, 'a-class-name', false, 'another-one', undefined)} />
)
U.pure(Component)U.pure wraps the given component inside a
PureComponent.
U.pure can be used for preventing unnecessary rerenders when a Karet component
is used as a child of a React component that rerenders its children even when
their props do not change. See also U.toReact.
U.toKaret(ReactComponent)U.toKaret converts a React component that takes plain value properties to a
Karet component that can be given observable properties. U.toKaret is useful
when using React components, such as React
Select, as children of Karet
components and with observable rather than plain value properties. U.toKaret
is a synonym for fromClass from
the Karet library.
U.toReact(KaretComponent)U.toReact converts a Karet component that expects observable properties and
should not be rerendered unnecessarily into a React component that takes plain
value properties. U.toReact may be needed particularly when a Karet component
is controlled by a higher-order React component, such as React
Router, because Karet components
typically (are not and) must not be rerendered unnecessarily. U.toReact is
equivalent to U.toReactExcept(() => false). See also
U.pure.
U.toReactExcept(propName => boolean, KaretComponent)U.toReactExcept converts a Karet component that expects observable properties
and should not be rerendered unnecessarily into a React component that takes
plain value properties. The given predicate is used to determine which
properties must not be converted to observable properties. Like
U.toReact, U.toReactExcept may be needed particularly when a
Karet component is controlled by a higher-order React component, such as React
Router, because Karet components
typically (are not and) must not be rerendered unnecessarily. See the Calmm
function to React class CodeSandbox for an
example.
U.IdentityLatestU.IdentityLatest is a Static Land compatible algebra module over properties,
like U.Latest, or plain values.
U.LatestU.Latest is a Static Land compatible algebra module over properties from which
only the latest value is propagated. Currently it implements the
monad
algebra.
For example:
log(
L.traverse(
U.Latest,
x => U.startWith(undefined, U.later(x*1000, x)),
L.elems,
[1, 2, 3]
)
)
U.and(...any)U.and is a lazy variadic logical and over potentially observable properties.
U.and(l, r) does not subscribe to r unless l is truthy.
U.cond(...[condition, consequent][, [alternative]])U.cond allows one to express a sequence of conditionals. U.cond translates
to a nested expression of U.ifElses.
U.cond( [ condition, consequent ]
, ...
[ , [ alternative ] ] )
The last [ alternative ], which, when present, needs to be a singleton array,
is optional.
U.ifElse(condition, consequent, alternative)U.ifElse is basically an implementation of the conditional operator condition
? consequent : alternative for observable properties.
U.ifElse(condition, consequent, alternative) is roughly shorthand for
U.toProperty(
U.flatMapLatest(boolean => (boolean ? consequent : alternative), condition)
)
except that the consequent and alternative expressions are only evaluated
once.
U.not(any)U.not is a logical negation over a potentially observable property.
U.or(...any)U.or is a lazy variadic logical or over potentially observable properties.
U.or(l, r) does not subscribe to r unless l is falsy.
U.unless(condition, alternative)U.unless(condition, alternative) is shorthand for U.ifElse(condition,
undefined, alternative).
U.when(condition, consequent)U.when(condition, consequent) is shorthand for U.ifElse(condition,
consequent, undefined).
U.animationSpan(milliseconds)U.animationSpan creates a property of increasing values from 0 to 1 for the
given duration in milliseconds on each animation frame as generated by
requestAnimationFrame.
See the live Animation CodeSandbox for an example.
U.combine([...any], fn)U.combine is a special purpose Kefir
observable property combinator designed for combining properties for a sink that
accepts both observable properties and constant values such as the Reactive VDOM
of Karet.
Unlike typical property combinators, when U.combine is invoked with only
constants (no properties), then the result is computed immediately and returned
as a plain value. This optimization eliminates redundant properties.
The basic semantics of U.combine can be described as
U.combine(xs, fn) === Kefir.combine(xs, fn).skipDuplicates(R.identical)
where Kefir.combine and
skipDuplicates come from
Kefir and R.identical from
Ramda. Duplicates are skipped, because that can reduce
unnecessary updates. Ramda's R.identical provides a semantics of equality
that works well within the context of embedding properties to VDOM.
Unlike with Kefir.combine, any of
the argument xs given to U.combine is allowed to be
In other words, U.combine also provides functionality similar to
Bacon.combineTemplate.
Note: U.combine is carefully optimized for space—if you write equivalent
combinations using Kefir's own operators, they will likely take more memory.
U.lift((...) => ...)U.lift allows one to lift a function operating on plain values to a function
that operates both on plain values and on observable properties. When given
only plain values, the resulting function returns a plain value. When given
observable properties, the resulting function returns an observable property of
results. See also U.liftRec
For example:
var includes = U.lift( (xs, x) => xs.includes(x) )
var obsOfBooleans = includes(obsOfArrays, obsOfValues)
U.lift works well for simple functions that do not return functions. If you
need to lift higher-order functions that return new functions that should also
be lifted, try U.liftRec.
U.liftRec((...) => ...)U.liftRec allows one to lift a function operating on plain values to a
function that operates both on plain values and on observable properties. When
given only plain values, the resulting function returns a plain value. When
given observable properties, the resulting function returns an observable
property of results. See also U.lift.
For example:
var either = U.liftRec(R.either)
var equals = U.lift(R.equals)
var obsOfBooleans = either(R.equals(obs1), R.equals(obs2))
U.liftRec is designed to be very simple to use. For example, the Kefir
Ramda
library simply wraps every Ramda function with liftRec
and this results in a library that has essentially the same signature (currying
and variable argument functions work the same) as Ramda except that the
functions also work on Kefir observables.
Kefir is a traditional JavaScript library that provides a fluent API using method chaining. Karet Util supports more functional style JavaScript by providing curried functions for programming with Kefir. The functions provided by Karet Util also try to avoid constructing observables unnecessarily.
The following are simply links to the relevant Kefir documentation:
U.changes(observable) ⌘U.debounce(ms, observable) ⌘U.delay(ms, observable) ⌘U.flatMapErrors(value => observable, observable) ⌘U.flatMapLatest(value => observable, observable) ⌘U.flatMapParallel(value => observable, observable) ⌘U.flatMapSerial(value => observable, observable) ⌘U.foldPast((state, value) => state, state, observable) ⌘U.fromEvents(target, eventName, transform) ⌘U.ignoreErrors(observable) ⌘U.ignoreValues(observable) ⌘U.interval(ms, value) ⌘U.later(ms, value) ⌘U.mapValue(value => value, observable) ⌘U.never ⌘ — Note that this is
not a function!U.parallel([...observables]) ⌘U.sampledBy(eventStream, property) ⌘U.serially([...observables]) ⌘U.skipDuplicates(equality, observable) ⌘U.skipFirst(number, observable) ⌘U.skipFirstErrors(n, observable) ⌘U.skipUnless(predicate, observable) ⌘U.takeFirst(number, observable) ⌘U.takeFirstErrors(number, observable) ⌘U.takeUntilBy(eventStream, observable) ⌘U.throttle(ms, observable) ⌘U.toObservable(observable) ⌘U.toProperty(observable) ⌘U.consume(action, observable)U.consume creates a property that simply immediately produces undefined and
subscribes to the given observable whose values it passes to the given action
for as long as the returned property is subscribed to. U.consume can be used
for executing side-effects during the time that a component is mounted. See
also U.sink.
For example:
var DocumentTitle = ({title}) => (
<React.Fragment>
{U.consume(title => {
if (typeof document !== 'undefined') document.title = title
}, title)}
</React.Fragment>
)
U.endWith(value, observable)U.endWith creates an observable that ends with the given value. That is,
after the given observable ends, the given value is emitted.
U.lazy(() => observable)U.lazy allows to create an observable lazily.
For example, one use case for U.lazy is to create cyclic observables:
var sequence = ['⠋', '⠙', '⠸', '⠴', '⠦', '⠇']
var loop = () =>
U.serially([U.serially(sequence.map(U.later(100))), U.lazy(loop)])
See the live Login CodeSandbox for an example.
U.fromPromise(() => promise | {ready, abort})U.fromPromise converts a thunk that returns a promise or an object of the
shape {ready, abort} where ready is a promise and abort is an action that
aborts the promise into a Kefir property. The thunk is invoked once when the
property is subscribed to for the first time. If an abort action is defined
and all subscriptions of the property are closed before the promise resolves,
the property is ended and the abort action is called once.
For example:
var fetchJSON =
typeof AbortController === 'undefined'
? (url, params = {}) =>
U.fromPromise(() => fetch(url, params).then(res => res.json()))
: (url, params = {}) =>
U.fromPromise(() => {
const controller = new AbortController()
return {
ready: fetch(url, {...params, signal: controller.signal}).then(
res => res.json()
),
abort() {
controller.abort()
}
}
})
See the live GitHub search CodeSandbox for an example.
Note that U.fromPromise is not the same as Kefir's
fromPromise.
U.sink(observable)U.sink creates a property that simply immediately produces undefined and
subscribes to the given observable for as long as the returned sink is
subscribed to. See also U.consume.
U.skipIdenticals(observable)U.skipIdenticals is shorthand for
U.skipDuplicates(Object.is).
U.skipWhen(predicate, observable)U.skipWhen(predicate) is shorthand for U.skipUnless(x =>
!predicate(x)).
U.startWith(value, observable)U.startWith creates a property that starts with the given value. It uses the
toProperty method of Kefir.
U.template([ ... ] | { ... })U.template composes an observable property from an arbitrarily nested template
of objects and arrays observables.
For example:
var abProperty = U.template({a: anObservable, b: anotherObservable})
abProperty instanceof Kefir.Observable // true
U.on({value, error, end}, observable)U.on subscribes to an observable and dispatches the events to the actions
specified in the template.
Note that explicitly subscribing to an observable should be done very rarely in a Karet application! Full Karet applications can be written with zero uses of explicit observable subscriptions, because the Reactive VDOM of Karet automatically subscribes to and unsubscribes from observables. Nevertheless, it can sometimes be convenient to subscribe explicitly to observables to perform side-effects.
For example:
U.thru(
observable,
...,
U.on({
value: value = console.log(value)
})
)
Standard JavaScript functions only operate on plain values. Karet Util provides lifted versions of some useful standard JavaScript functions. The below just directly links to relevant documentation in MDN.
U.decodeURI(string) ⌘U.decodeURIComponent(string) ⌘U.encodeURI(string) ⌘U.encodeURIComponent(string) ⌘U.abs(x) ⌘U.acos(x) ⌘U.acosh(x) ⌘U.asin(x) ⌘U.asinh(x) ⌘U.atan(x) ⌘U.atanh(x) ⌘U.atan2(y, x) ⌘U.cbrt(x) ⌘U.ceil(x) ⌘U.clz32(x) ⌘U.cos(x) ⌘U.cosh(x) ⌘U.exp(x) ⌘U.expm1(x) ⌘U.floor(x) ⌘U.fround(x) ⌘U.hypot(...xs) ⌘U.imul(x, y) ⌘U.log(x) ⌘U.log1p(x) ⌘U.log10(x) ⌘U.log2(x) ⌘U.max(...xs) ⌘U.min(...xs) ⌘U.pow(x, y) ⌘U.round(x) ⌘U.sign(x) ⌘U.sin(x) ⌘U.sinh(x) ⌘U.sqrt(x) ⌘U.tan(x) ⌘U.tanh(x) ⌘U.trunc(x) ⌘
document.querySelector('.loading-message').className = "loading-hidden";
ga('send', 'event', 'completed', 'load', Math.round((Date.now() - startTime)/1000));
accelerate_klipse();