-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
127 lines (118 loc) · 3.86 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
var loop = require('virtual-raf')
var createStore = require('store-emitter')
var assert = require('assert')
var xtend = require('xtend')
/**
* Create the app.
* @name createVirtualApp
* @param {Object} container – DOM element that will act as parent element
* @param {Object} vdom – the full virtual-dom module returned by `require('virtual-dom')`
* @example
* var createVirtualApp = require('virtual-app')
*
* var app = createVirtualApp(document.body, require('virtual-dom'))
*/
module.exports = function createVirtualApp (vdom) {
assert.equal(typeof vdom, 'object', 'vdom must be an object')
var app = {
vdom: vdom
}
/**
* Start the app.
* @name app.start
* @param {Function} modifier – function that determines how the state will change based on the action
* @param {Object} initialState – the state of the application when it loads
* @example
* function modifier (action, state) {
* if (action.type === 'example') {
* return { example: true }
* }
* }
*
* var render = app.start(modifier, {
* example: false
* })
*
* render(function (state) {
* if (state.example) {
* return app.h('h1', 'this is an example')
* } else {
* return app.h('h1', 'what i thought this was an example')
* }
* })
*/
app.start = function virtualApp_start (modifier, initialState) {
assert.equal(typeof modifier, 'function', 'modifier must be a function')
assert.equal(typeof initialState, 'object', 'initialState must be an object')
/**
* Trigger an event that gets passed through the modifier function to change the state. A `type` property is required. You can add any other arbitrary properties.
* @name app.store
* @param {Object} action
* @param {String} action.type – an identifier for the type of the action
* @example
* app.store({
* type: 'example'
* example: true
* })
*/
app.store = createStore(modifier, initialState)
/**
* Render the application. This function is returned by the `app.start()` method.
* @name render
* @param {Function} callback – define the virtual tree of your application and return it from this callback
* @return {Object} DOM node tree
* @example
* var render = app.start(modifier, { food: 'pizza' })
*
* render(function (state) {
* return app.h('h1', state.food)
* })
*/
return function render (callback) {
app.tree = loop(initialState, callback, vdom)
if (typeof window !== 'undefined') {
app.store.on('*', function (action, state) {
app.tree.update(state)
})
}
return app.tree.render()
}
}
/**
* Event listener
* @name app.on
* @param {String} event – can be an asterisk `*` to listen to all actions or the type of a specific action
* @param {Function} callback – callback that provides `action`, `state`, and `oldState` arguments
* @example
* app.on('*', function (action, state, oldState) {
* // do something with the new `state`
* })
*/
app.on = function virtualApp_on (event, callback) {
app.store.on(event, callback)
}
/**
* virtual-dom `h` function.
* @name app.h
*/
app.h = function virtualApp_element (selector, options, children) {
return vdom.h(selector, options, children)
}
/**
* Bind an event to a component. Convenience wrapper around `app.store`.
* @name app.send
* @param {Object} action
* @param {String} action.type – an identifier for the type of the action
* @param {String} flag – call preventDefault on event (default: true)
* @example
* app.h('button', { onclick: app.send({ type: 'increment' })}, 'click me')
*/
app.send = function virtualApp_send (action, flag) {
if (typeof flag === undefined) flag = true
return function virtualApp_send_thunk (e) {
if (flag && e && e.preventDefault) e.preventDefault()
app.store(action)
}
}
return app
}