1 | import curry from 'ramda/src/curry'
|
2 |
|
3 | import { createStore, applyMiddleware } from 'redux'
|
4 | import thunk from 'redux-thunk'
|
5 |
|
6 | import diff from 'virtual-dom/diff'
|
7 | import patch from 'virtual-dom/patch'
|
8 | import createElement from 'virtual-dom/create-element'
|
9 |
|
10 | import State from './State'
|
11 | import * as delegator from './dom/delegator'
|
12 |
|
13 |
|
14 | delegator.listen()
|
15 |
|
16 | const createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
|
17 |
|
18 |
|
19 | export function start (component) {
|
20 | const { init, update, view } = component
|
21 | const [initialState, initialAction] = handleInit(init)
|
22 |
|
23 |
|
24 | let dispatch = x => x
|
25 |
|
26 | const store = createStoreWithMiddleware((state = initialState, action) => {
|
27 | const newState = update(state, action, dispatch)
|
28 |
|
29 | return (typeof newState === 'undefined') ? state : newState
|
30 | })
|
31 |
|
32 | dispatch = makeDispatcher(store)
|
33 |
|
34 | if (initialAction) {
|
35 | store.dispatch(initialAction)
|
36 | }
|
37 |
|
38 | let tree = view(initialState, dispatch)
|
39 | const rootNode = createElement(tree)
|
40 |
|
41 | store.subscribe(() => {
|
42 | tree = patchTree(
|
43 | rootNode,
|
44 | tree,
|
45 | view(store.getState(), dispatch)
|
46 | )
|
47 | })
|
48 |
|
49 | return rootNode
|
50 | }
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 | function makeDispatcher (store) {
|
57 | return action => {
|
58 | return event => {
|
59 | if (event) {
|
60 | action.$event = event
|
61 |
|
62 | if (action.$fwdAction) {
|
63 | action.$fwdAction.$event = event
|
64 | }
|
65 | }
|
66 |
|
67 | store.dispatch(action)
|
68 | }
|
69 | }
|
70 | }
|
71 |
|
72 |
|
73 | function patchTree (rootNode, oldTree, newTree) {
|
74 | patch(rootNode, diff(oldTree, newTree))
|
75 |
|
76 | return newTree
|
77 | }
|
78 |
|
79 |
|
80 | export function initializeComponent ({ init }, dispatch) {
|
81 | const [initialState, initialAction] = handleInit(init)
|
82 |
|
83 | if (dispatch && initialAction) {
|
84 | dispatch(initialState)(initialAction)()
|
85 | }
|
86 |
|
87 | return initialState
|
88 | }
|
89 |
|
90 |
|
91 | function handleInit (init) {
|
92 | const _res = init()
|
93 | const res = Array.isArray(_res) ? _res : [_res]
|
94 |
|
95 | return [new State(res[0]), res[1]]
|
96 | }
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | export const forwardDispatch = curry((action, dispatch, state) => {
|
104 | return forwardAction => {
|
105 | if (typeof forwardAction === 'function') {
|
106 |
|
107 |
|
108 |
|
109 | return dispatch(rawDispatch => {
|
110 | const getState = () => state
|
111 | const fwd = forwardDispatch(action, rawDispatch, state)
|
112 |
|
113 | forwardAction(fwd, getState)
|
114 | })
|
115 | }
|
116 |
|
117 |
|
118 | return dispatch(Object.assign({}, action, { $fwdAction: forwardAction }))
|
119 | }
|
120 | })
|