-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
116 lines (97 loc) · 2.5 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
/**
* @module dynamic-component
* (c) 2016 Dhruv Dang
*/
"use strict";
var domDelegator = require("dom-delegator");
var virtualDOM = require("virtual-dom");
var window = require("global/window");
var cloneDeep = require("lodash/cloneDeep");
var assign = require("lodash/assign");
var isPlainObject = require("lodash/isPlainObject");
var isFunction = require("lodash/isFunction");
var noop = require("lodash/noop");
var svg = require("virtual-dom/virtual-hyperscript/svg");
var h = virtualDOM.h;
var patch = virtualDOM.patch;
var diff = virtualDOM.diff;
var create = virtualDOM.create;
function bind (state, render, element) {
// set up the dom delegator to delegate DOM events.
// it's okay to run this multiple times, as DOM delegator
// ensures it only affects global state once.
domDelegator();
var tree = render(state.get());
var root = create(tree);
element.appendChild(root);
state.subscribe(apply);
function apply (newState) {
var newTree = render(newState);
var patches = diff(tree, newTree);
root = patch(root, patches);
tree = newTree;
}
return root;
}
function createState (state) {
if (!isPlainObject(state)) {
state = {};
}
var subscriptions = [];
function get () {
return cloneDeep(state);
}
var publishQueued = false;
function publish () {
var newState = get();
publishQueued = false;
subscriptions.forEach(function (handler) {
handler(newState);
});
}
function queuePublish () {
if (!publishQueued) {
nextTick(publish);
publishQueued = true;
}
}
function nextTick (fn) {
if (isFunction(window.requestAnimationFrame)) {
window.requestAnimationFrame(fn);
} else {
setTimeout(fn, 0);
}
}
return {
get: get,
set: function (newValues, silent, shouldGet) {
// shallow assign
assign(state, newValues);
// emit new state to subscriptions
if (!silent) {
queuePublish();
}
// return the newState if requested
if (shouldGet) {
return get();
}
},
subscribe: function (handler) {
if (subscriptions.indexOf(handler) === -1 && isFunction(handler)) {
subscriptions.push(handler);
var i = subscriptions.length - 1;
return function unsubscribe () {
subscriptions.splice(i, 1);
};
} else {
return noop;
}
}
};
}
module.exports = {
h: h,
svg: svg,
createState: createState,
bind: bind
};