This repository has been archived by the owner on Jan 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
lib.js
123 lines (101 loc) · 3.39 KB
/
lib.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
export default ({
model = {},
actions = {},
middlewares = [],
autostart = true,
callback
}) => {
const calls = []
let subscribers = []
let SST = JSON.parse(JSON.stringify(model))
const nextTick = (typeof window !== 'undefined' && window.document && window.document.createElement)
? (requestAnimationFrame || setTimeout)
: (fn) => fn()
// @Setters
const setActions = (newlist) => {
actions = newlist
}
const set = lambda => {
lambda(SST)
subscribers.forEach(subscriber => subscriber(SST, { haschanged: true }))
}
// @Getters
const getState = () => {
return Object.assign({}, SST)
}
const getActions = () => {
return actions
}
const subscribe = ( fnOrObject, {autostart = false} = {} ) => {
if( !fnOrObject ) return
if (fnOrObject.call) {
fnOrObject.ref = fnOrObject
subscribers.push(fnOrObject)
if( autostart )
fnOrObject(Object.assign({}, SST), {action:null, payload:null, haschanged:true})
} else {
Object.keys(fnOrObject).forEach( action => {
const handler = fnOrObject[action]
const fn = (state, options) => {
if (options.action in fnOrObject)
fnOrObject[options.action](state, options)
}
fn.ref = handler
subscribers.push(fn)
if (autostart)
fn( Object.assign({}, SST), {action, payload:null, haschanged :true} )
})
}
}
const unsubscribe = (fn) => {
subscribers = subscribers.filter( subscriber => subscriber.ref != fn )
}
const dispatch = (action, payload) => {
return new Promise(resolve => {
calls.push({ action, payload })
if (calls.length == 1) {
nextTick(() => {
while (calls.length)
_dispatch(calls[0].action, calls[0].payload, resolve)
})
}
})
}
const _dispatch = (action, payload, resolve) => {
let haschanged = false
if (action in actions) {
const newstate = Object.assign({}, SST)
const result = actions[action](newstate, payload, api)
if (result) {
SST = Object.assign(SST, result)
haschanged = true
}
}
calls.shift()
if (!calls.length) {
const params = { action, payload, haschanged }
subscribers.forEach(subscriber => subscriber(SST, params))
resolve(SST, params)
}
}
const when = (action) => {
return new Promise((resolve) => {
const handler = (state, { payload }) => {
resolve(Object.assign({}, state, payload))
unsubscribe(handler)
}
subscribe({ [action]: handler })
})
}
//@Api
const api = { set, when, getState, dispatch, subscribe, unsubscribe, getActions, setActions }
//@Hooks for render functions
if( callback ){
subscribe((state, options) => options.haschanged ? callback(state, options) : null)
autostart ? callback(SST) : null
}
//@Middlewares
middlewares.forEach(middleware => middleware(api))
// @Exposing api
return api
}