1 | function systemReducer(state, action) {
|
2 | switch (action.type) {
|
3 | case "SET": {
|
4 | const { name, value } = action.payload
|
5 | return {
|
6 | ...state,
|
7 | [name]: value,
|
8 | }
|
9 | }
|
10 | case "MERGE": {
|
11 | return {
|
12 | ...state,
|
13 | ...action.payload,
|
14 | }
|
15 | }
|
16 | }
|
17 | }
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | export function configure(
|
33 | { update = {}, middleware = [], derivations = {}, initialState = {} },
|
34 | node
|
35 | ) {
|
36 | let subscribers = []
|
37 | let state
|
38 | let updatedCallback = () => {}
|
39 |
|
40 | function updateState(o) {
|
41 | state = { ...o }
|
42 | for (let k in derivations) {
|
43 | state[k] = derivations[k](o)
|
44 | }
|
45 | }
|
46 |
|
47 | updateState(initialState)
|
48 |
|
49 | function getState() {
|
50 | return { ...state }
|
51 | }
|
52 |
|
53 | function subscribe(fn) {
|
54 | subscribers.push(fn)
|
55 | }
|
56 |
|
57 | function flush() {
|
58 | subscribers.forEach((fn) => fn())
|
59 | subscribers = []
|
60 | }
|
61 |
|
62 | function onUpdate(fn) {
|
63 | updatedCallback = fn
|
64 | }
|
65 |
|
66 | function dispatch(action) {
|
67 | const { type } = action
|
68 | if (type === "SET" || type === "MERGE") {
|
69 | updateState(systemReducer(getState(), action))
|
70 | } else {
|
71 | if (middleware.length) {
|
72 | let mw = middleware.slice()
|
73 |
|
74 | let next = (action) => {
|
75 | if (mw.length) {
|
76 | let x = mw.shift()
|
77 |
|
78 | if (action.type in x) {
|
79 | x[action.type](action, next, {
|
80 | getState,
|
81 | dispatch,
|
82 | afterNextRender: subscribe,
|
83 | })
|
84 | } else {
|
85 | next(action)
|
86 | }
|
87 | } else if (action.type in update) {
|
88 | updateState(update[action.type](getState(), action))
|
89 | }
|
90 | }
|
91 |
|
92 | let x = mw.shift()
|
93 |
|
94 | if (type in x) {
|
95 | x[type](action, next, {
|
96 | getState,
|
97 | dispatch,
|
98 | afterNextRender: subscribe,
|
99 | })
|
100 | } else {
|
101 | next(action)
|
102 | }
|
103 | } else if (type in update) {
|
104 | updateState(update[type](getState(), action))
|
105 | }
|
106 | }
|
107 | updatedCallback()
|
108 | }
|
109 |
|
110 | for (let actionName in update) {
|
111 | if (actionName.startsWith("$")) {
|
112 | node.addEventListener(actionName, ({ detail }) => dispatch(detail))
|
113 | }
|
114 | }
|
115 |
|
116 | return {
|
117 | dispatch,
|
118 | getState,
|
119 | onUpdate,
|
120 | flush,
|
121 | }
|
122 | }
|