forked from transloadit/uppy
/
index.js
94 lines (78 loc) · 2.38 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
const { nanoid } = require('nanoid/non-secure')
// Redux action name.
const STATE_UPDATE = 'uppy/STATE_UPDATE'
// Pluck Uppy state from the Redux store in the default location.
const defaultSelector = (id) => (state) => state.uppy[id]
/**
* Redux store.
*
* @param {object} opts.store - The Redux store to use.
* @param {string} opts.id - This store instance's ID. Defaults to a random string.
* If you need to access Uppy state through Redux, eg. to render custom UI, set this to something constant.
* @param {Function} opts.selector - Function, `(state) => uppyState`, to pluck state from the Redux store.
* Defaults to retrieving `state.uppy[opts.id]`. Override if you placed Uppy state elsewhere in the Redux store.
*/
class ReduxStore {
static VERSION = require('../package.json').version
#id
#selector
#store
constructor (opts) {
this.#store = opts.store
this.#id = opts.id || nanoid()
this.#selector = opts.selector || defaultSelector(this.#id)
// Calling `setState` to dispatch an action to the Redux store.
// The intent is to make sure that the reducer has run once.
this.setState({})
}
setState (patch) {
this.#store.dispatch({
type: STATE_UPDATE,
id: this.#id,
payload: patch,
})
}
getState () {
return this.#selector(this.#store.getState())
}
subscribe (cb) {
let prevState = this.getState()
return this.#store.subscribe(() => {
const nextState = this.getState()
if (prevState !== nextState) {
const patch = getPatch(prevState, nextState)
cb(prevState, nextState, patch)
prevState = nextState
}
})
}
[Symbol.for('uppy test: get id')] () {
return this.#id
}
}
function getPatch (prev, next) {
const nextKeys = Object.keys(next)
const patch = {}
nextKeys.forEach((k) => {
if (prev[k] !== next[k]) patch[k] = next[k]
})
return patch
}
function reducer (state = {}, action) {
if (action.type === STATE_UPDATE) {
const newState = { ...state[action.id], ...action.payload }
return { ...state, [action.id]: newState }
}
return state
}
function middleware () {
// Do nothing, at the moment.
return () => (next) => (action) => {
next(action)
}
}
module.exports = ReduxStore
module.exports.ReduxStore = ReduxStore
module.exports.STATE_UPDATE = STATE_UPDATE
module.exports.reducer = reducer
module.exports.middleware = middleware