Literal templates are rendered in a scope that contains some useful objects and functions.
The data
object is the data passed into the template to be rendered:
${ data.name }
Other templates can be included with include()
function:
${ include('#some-other-template', data) }
Expressions that return promises or streams cause the DOM to be updated
when values are resolved. The events()
function, for example, returns a
mappable stream of events:
${ events('hashchange', window).map((e) => location.hash) }
Some functions are simply built-ins, aliased for brevity (it is nicer to read
${ values(data) }
than ${ Object.values(data) }
within the constraints of a
template).
data
The main object passed into the template carrying data. This object is special. When it mutates, the DOM re-renders.
this
The current renderer. Normally this should not be touched, and is provided for debugging.
body
An alias of document.body
.
element
The element enclosing the current template tag.
host
Where this literal template renders the shadow DOM of a custom element, host
refers to the custom element.
shadow
Where this literal template renders the shadow DOM of a custom element, shadow
refers to the custom element’s shadow root.
nothing
A frozen array-like and stream-like object that contains no value.
assign(a, b, …)
Alias of Object.assign()
.
by(fn, a, b)
For sorting arrays. Compares fn(a)
against fn(b)
and returns -1
, 0
or
1
. Partially applicable. To sort an array of objects by their ids:
array.sort(by(get('id')))
ceil(n)
Alias of Math.ceil()
.
clamp(min, max, n)
Clamps number n
to the limits min
to max
. Values of n
lower than min
return min
, and those higher than max
return max
.
clock(duration)
If duration
is a number, returns a stream of DOM timestamps at duration
seconds apart.
${ clock(1).map(floor) }
${ clock(1).map(floor) }
If duration
is "frame"
, returns a stream of DOM timestamps of animation
frames.
${ clock('frame').map((time) => time.toFixed(2)) }
${ clock('frame').map((time) => time.toFixed(2)) }
delegate(map)
Takes an object map of functions keyed to selectors, and returns a function that handles event objects, delegating them to the first function whose selector matches the event target. Functions are passed the target node and the event object, plus any other arguments passed to the handler.
delegate({
'button': (button, event) => {}
})
entries(object)
Alias of Object.entries()
.
equals(a, b)
Compares a
and b
for deep equality and returns true
where they are equal,
otherwise false.
events(type, node)
Returns a mappable stream of events heard on node
.
${ events('click', element).map((e) => e.target.id) }
The first parameter may also be an object with a type
property. If the
object has a select
property that is a CSS selector, events are delegated
from matching targets:
${ events({ type: 'click', select: '[name="button"]' }, element)
.map((e) => e.target.value) }
Other properties are passed to addEventListener options, for passive and capture phase event binding:
${ events({ type: 'scroll', passive: true, capture true }, window)
.map((e) => window.scrollTop) }
Stopping an event stream removes event listeners. Streams returned from expressions are automatically stopped when their renderers are removed.
floor(n)
Alias of Math.floor()
.
get(path, object)
Gets the value of path
in object
, where path
is a string in JS
dot-notation. Where a path does not lead to a value, returns undefined
:
${ get('path.to.value', data) }
Numbers are accepted as path components:
${ get('array.0', data) }
id(value)
Returns value
.
include(src, data)
Includes a template identified by src
, passing in an object to render in that
template as data
. In production it is recommended that src
is a fragment
identifier referring to the id of a template already in the DOM:
${ include('#another-template', data) }
The include
function is partially applicable, making it easy to use for
looping over an array to return an array of rendered templates:
${ data.array.map(include('#list-item')) }
keys(object)
Alias of Object.keys()
.
last(array)
Returns the last value in an array.
matches(selector, object)
For filtering and pattern matching. Returns true where all the properties
of selector
object are strictly equal to the same properties of object
.
Note that object
may have more properties than selector
.
const vegetarian = menu.filter(matches({ vegetable: true }));
noop()
Does nothing, returns undefined.
overload(fn, map)
For function overloading. Takes a fn
that returns a string key, and a map
object of functions stored against keys. Returns a function that calls the
function at the key generated by calling fn()
with all arguments.
Where a key is not in map
but map
contains the property 'default'
,
that default function is called. Where there is no default function an error
is thrown.
var handleEvent = overload((e) => e.type, {
click: (e) => {...},
input: (e) => {...},
default: (e) => {...}
});
paramify(object)
Turns an object with enumerable properties into a native URL search parameters object. Rejects undefined properties and flattens out array values.
print(data)
Where window.DEBUG
was falsy at the time Literal is imported, print()
does
nothing.
Prints an object or objects to the DOM as a debug message.
<template is="literal-template" data="../../package.json">
${ print(data) }
</template>
Renders as:
${ print(data) }request(method, url)
Uses fetch()
to send a request to url
. Returns a promise.
${ request(method, url).then(...) }
To send data with the request:
${ request(method, url, data).then(...) }
Where type
is "GET"
, data
is serialised and appended to the URL,
otherwise it is sent as a request body.
A 4th parameter may be a content type string or a headers object
(in which case it must have a 'Content-Type'
property).
${ request(method, url, data, headers).then(...) }
round(n, value)
Round value
to the nearest multiple of n
.
slugify(string)
Replaces any series of non-word characters with a '-'
and lowercases the rest.
slugify('Party on #mydudes!') // 'party-on-mydudes'
Stream.combine(object)
Creates a stream of objects containing the latest values of all streams and
promises in object
, as soon as they become active or resolved.
Stream.combine({ a: stream, b: promise }).each((object) => {
// object.a and object.b are values
});
If object
contains properties that are not streams or promises, those are
also set on streamed objects.
Stream.combine({ a: stream, b: promise, c: 5 }).each((object) => {
// object.c is 5
});
Output objects are created using the constructor of the input object
,
making it possible to use an array or other object as input and expect an
array or other object as output.
Stream.combine([promise, stream]).each((object) => {
// object is an Array
});
The stream may be made mutable by passing true
(or an options object with
mutable
set to true
) as a second parameter. In this case no new objects
are constructed, instead the input object
is mutated and pushed to the
output stream. This may be a Good Idea when it is necessary to avoid garbage
collection, such as when animating.
Stream.combine({ a: stream, b: promise }, true).each((object) => {
// object is the input object, properties a and b are now values
});
Stream.from(source)
Creates a stream from source
, which may be a pipeable (an object with
.pipe()
and .stop()
methods), an array (or array-like), or a promise.
Stream.merge(stream1, stream2, …)
Creates a stream by merging values from any number of input streams into a single output stream. Values are emitted in the time order they are received from inputs.
Stream.merge(stream1, stream2).each((value) => {
// value is from stream1 or stream 2
});
Stream.of(value1, value2, …)
Creates a pushable BufferStream from the given parameters.
sum(a, b)
Returns the sum of b + a
.
translate(key)
Looks up an alternative value stored by key
in a window.translations
object, if it exists. A super simple translation mechanism, but requires
window.translations
to be populated.
${ translate('Go to homepage') }
trigger(type, node)
Triggers event of type
on node
. Returns false
if the event default was
prevented, otherwise true
.
trigger('activate', node);
Alternatively the first argument may be an object with a type
property, and
optionally detail
, which must be an object, and bubbles
, cancelable
and
composed
options, which determine the behaviour of the event.
trigger({
type: 'activate',
detail: {...},
bubbles: true,
cancelable: true,
composed: false
}, node);
values()
Alias of Object.values()
.
px(value)
Takes a number in pixels or a string of the form '10px'
, '10em'
, '10rem'
,
'100vw'
, '100vh'
, '100vmin'
or '100vmax'
, and returns a numeric value
in pixels.
em(value)
Takes numeric value in px, or CSS length of the form '10px'
, and returns
a numeric value in em
, eg. 0.625
. Depends on the user defined browser
font-size
.
rem(value)
Takes numeric value in px, or CSS length of the form '10px'
, and returns
a numeric value in rem
, eg. 0.625
. Depends on the font-size
of the
documentElement.
vw(value)
Takes number in pixels or CSS length of the form '10em'
and returns a
numeric value in vw
, eg. 120
. Depends on the width of the viewport at
render time.
vh(value)
Takes number in pixels or CSS length of the form '10em'
and returns a
numeric value in vh
, eg. 120
. Depends on the height of the viewport at
render time.
How evaluated expressions are rendered into the DOM depends upon their type.
Promises are resolved before they render, arrays are flattened and joined without spaces or commas, and streams are re-rendered every time they emit a new value.
Literal flattens nested collections – a promise of a stream of arrays of strings will render as a string as its values arrive.
False-y values, other than false
itself, don’t render at all, so expressions
may evaluate to undefined
or null
and go unseen.
Type | Expression | Renders as |
---|---|---|
undefined | ${ undefined } |
${ undefined } |
null | ${ null } |
${ null } |
NaN | ${ NaN } |
${ NaN } |
String | ${ 'Hello' } |
${ 'Hello' } |
Boolean | ${ true }, ${ false } |
${ true }, ${ false } |
Number | ${ 100.3 } |
${ 100.3 } |
Infinity | ${ Infinity }, ${ -Infinity } |
${ Infinity }, ${ -Infinity } |
Function | ${ function name(param) {} } |
${ function name(param) {} } |
Arrow | ${ (param) => {} } |
${ (param) => {} } |
RegExp | ${ /^regexp/ } |
${ /^regexp/ } |
Symbol | ${ Symbol('name') } |
${ Symbol('name') } |
Array | ${ [0, 1, 2, 3] } |
${ [0, 1, 2, 3] } |
Object | ${ { property: 'value' } } |
${ { property: 'value' } } |
Node | ${ document.createTextNode('Text') } |
${ document.createTextNode('Text') } |
Promise | ${ Promise.resolve('promise') } |
${ Promise.resolve('promise') } |
Stream | ${ events('pointermove', body) |
${ events('pointermove', body).map((e) => e.pageX.toFixed(1)) } |
Built by Stephen Band for
Cruncher.
Documentation set in Euclid
and Martian Mono. Fonts
used for documentation not included as part of the license covering the
use of Literal
.