Brisky is a lightning fast universal JS library for building state driven user interfaces.
It consist of multiple sub-modules, each module adding specific funcitonality
Find and create functional examples in our example repo.
First, let's start by displaying two DOM elements with hello
and world
as their content:
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({})
const element = {
container1: {
text: 'Hello'
},
container2: {
text: 'World!'
}
}
document.body.appendChild(render(element, state))
Notice that the object containing the content can be named anything, as long as you camelCase it, just like a normal JavaScript object. In this example container1
and container2
is used.
Here we are setting the state object
, containing hello
and world
.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
object: {
hello: 'Hello',
world: 'World!'
}
})
const element = {
$: 'object',
container1: {
text: {
$: 'hello'
}
},
container2: {
text: {
$: 'world'
}
}
}
document.body.appendChild(render(element, state))
Notice the $:
notation. In the above example, we subscribe to object
. This means that whenever object
changes, our two DOM-elements are updated with the new content.
Also notice the nested nature of subscriptions. The two containers inside are scoped from within object
, allowing them to grab hello
and world
directly.
The tag field allows you to render normal DOM elements. By default, every object you render to the DOM is a div
. You change this by defining a tag
type, e.g. tag: 'section'
.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({})
const element = {
title: {
tag: 'h1',
text: 'I am a title'
},
paragraph: {
tag: 'p',
text: 'I am a paragraph'
},
canvas: {
tag: 'canvas',
text: 'I am a canvas',
props: {
id: 'canvas',
width: '150',
height: '150'
}
}
}
document.body.appendChild(render(element, state))
Extending from the example above, we have props. These allow you to set and manipulate the different attributes in a tag.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
canvas: {
width: 150,
height: 150
}
})
const element = {
canvas: {
$: 'canvas',
tag: 'canvas',
text: 'I am a canvas',
props: {
id: 'canvas',
width: { $: 'width' },
height: { $: 'height' }
}
}
}
document.body.appendChild(render(element, state))
In this example we have an input field that overwrites state when enter is pressed. We are using brisky-events to make this happen.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
username: 'John Doe'
})
const element = {
input: {
tag: 'input',
props: { placeholder: 'Enter username' },
on: {
enter: (e, stamp) => {
e.state.root.set({ username: e.target.value }, stamp)
e.target.value = '' // Reset input field
}
}
}
}
document.body.appendChild(render(element, state))
In this example we have a DOM element with a 'current-time' class, displaying the time when in hours and minutes. Notice that a function can be hoisted outside the scope - this is just normal JS.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({})
const element = {
currentTime: {
class: 'current-time',
text: {
$transform: data => {
const time = new Date().getTime();
const hours = formatTime(time.getHours())
const minutes = formatTime(time.getMinutes())
return `${hours}:${minutes}`
}
}
}
}
function formatTime (value) {
return (value < 10 ? `0${value}` : value)
}
document.body.appendChild(render(element, state))
Using transform, you are able to take something from state, and manipulate your element based on it. In this example we have a counter that displays amount of todos left, counting the amount of todos in our state.
This is inherited from vigour-observable.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
todos: [
{ text: 'Finish todo' },
{ text: 'Rule the world' },
]
})
const element = {
$: 'todos',
counter: {
text: {
$: true,
$transform: state => {
var count = 0
state.each(item => {
count++
})
return `${count} items left`
}
}
}
}
document.body.appendChild(render(element, state))
Good practice entails not rendering something that isn't needed for the user. Brisky facilitates this by giving you the test
field.
Here we only render donaldsSecretBunker
if the username is Donald
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
username: 'Donald'
})
const element = {
$: '$test',
$test: state => {
const username = state.root.username.compute()
if (username === 'Donald') {
return true
}
return false
},
donaldsSecretBunker: {
contentInsideBobsBunker: {
text: 'Secret message for Donald'
}
}
}
document.body.appendChild(render(element, state))
To extend from this, you can subscribe to test multiple things in the state. A normal use-case could be when you subscribe to something specific, like we do here with username
:
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
username: 'Donald',
defconWarningLevel: '3'
})
const element = {
donaldsSecretBunker: {
$: 'username.$test',
$test: {
val: state => {
const username = state.root.username.compute()
if (username === 'Donald') {
return true
}
return false
},
$: {
$root: { defconWarningLevel: true }
}
},
contentInsideBobsBunker: {
text: 'Secret message for Donald'
}
}
}
document.body.appendChild(render(element, state))
The switch simply switches content based on the value it is subscribing to. You can use the switch to change content within a component or on an application level, switching out whole pages.
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({
current: 'home'
})
const element = {
$: 'current.$switch',
$switch: state => state.compute() ? 'home' : 'profile',
properties: {
home,
profile
}
}
const home = {
text: 'This is the default page'
}
const profile = {
text: 'This is the profile page'
}
document.body.appendChild(render(element, state))
The fragment resembles the behavior of DocumentFragment. For an comparative example of document fragment implementation, see JavaScript DocumentFragment.
Using DocumentFragments is faster than repeated single DOM node injection and allows developers to perform DOM node operations (like adding events) on new elements instead of mass-injection via innerHTML. Keep DocumentFragment close by when performing lots of DOM operations -- it could speed up your app considerably!
const render = require('brisky/render')
const s = require('vigour-state/s')
const state = s({})
const element = {
container: {
tag: 'fragment'
}
}
document.body.appendChild(render(element, state))