UNPKG

turbopug

Version:

No-junk JS component library with insignificant weight. All in one mush: Web-Components, Localization, Routing, Reactive binding, Debounce, Unique IDs, PSW hashing

116 lines (108 loc) 3.57 kB
export default class Store { #state; #reds; #rootSubs; #nameSubs; #stateGetter; constructor(reducers, initialState) { this.#state = new Map(); this.#reds = new Map(); this.#rootSubs = new Set(); this.#nameSubs = new Map(); const getter = {}; for (const [name, reduce] of Object.entries(reducers)) { this.#reds.set(name, reduce); this.on[name] = callback => { this.on(name, callback); }; this.off[name] = callback => { this.off(name, callback); }; this.send[name] = event => { this.send(name, event); }; Object.defineProperty(getter, name, { get: () => this.#state.get(name) }); } this.#stateGetter = Object.freeze(getter); if (initialState) { for (const [name, value] of Object.entries(initialState)) { this.#state.set(name, value); } } } on(...args) { if (args.length === 1) { this.#rootSubs.add(args[0]); } else if (args.length === 2) { const acc = this.#nameSubs.get(args[0]) || new Set(); acc.add(args[1]); this.#nameSubs.set(args[0], acc); } else { throw new Error('Store.on(name, callback) || Store.on(callback)'); } } off(...args) { if (args.length === 1) { this.#rootSubs.delete(args[0]); } else if (args.length === 2) { const acc = this.#nameSubs.get(args[0]); if (acc) { acc.delete(args[1]); if (acc.length === 0) { this.#nameSubs.delete(args[0]); } else { this.#nameSubs.set(args[0], acc); } } } else { throw new Error('Store.off(name, callback) || Store.off(callback)'); } } send(...args) { if (args.length === 1) { for (const [name, reduce] of this.#reds) { const oldVal = this.#state.get(name); const newVal = reduce(oldVal, args[0]); this.#processReduction(name, oldVal, newVal); } } else if (args.length === 2) { const reduce = this.#reds.get(args[0]); if (reduce) { const oldVal = this.#state.get(args[0]); const newVal = reduce(oldVal, args[1]); this.#processReduction(args[0], oldVal, newVal); } else { throw new Error(`Store.send(name, event) with unknown name: ${args[0]}`); } } else { throw new Error('Store.send(name, event) || Store.send(event)'); } } #processReduction(name, oldVal, newVal) { if (oldVal !== newVal) { this.#state.set(name, newVal); const acc = this.#nameSubs.get(name); if (acc) { for (let callback of acc) { callback(oldVal, newVal); } } for (let callback of this.#rootSubs) { callback(name, oldVal, newVal); } } } get state() { return this.#stateGetter; } merge(incomingState) { for (const [name, value] of Object.entries(incomingState)) { this.#state.set(name, value); } } has(name) { return this.#reds.has(name); } }