53 lines
1.2 KiB
JavaScript
53 lines
1.2 KiB
JavaScript
export class ChangeEvent extends Event {
|
|
constructor(...changes) {
|
|
super('change')
|
|
this.changes = changes
|
|
}
|
|
}
|
|
|
|
export class State extends EventTarget {
|
|
#target
|
|
#options
|
|
#queue
|
|
constructor(target={}, options={}) {
|
|
super()
|
|
this.#options = options
|
|
this.#target = target
|
|
this.proxy = new Proxy(target, {
|
|
set: (_target, prop, value) => { this.set(prop, value); return true },
|
|
get: (target, prop) => target[prop],
|
|
})
|
|
|
|
this.addEventListener
|
|
|
|
if (options.methods ?? true) {
|
|
this.addEventListener("change", ({changes}) => {
|
|
new Map(changes).forEach((value, prop) => {
|
|
if (`${prop}Changed` in this) this[`${prop}Changed`](value)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
set state(value) { this.proxy.state = value }
|
|
get state() { return this.proxy.state }
|
|
|
|
set(prop, value) {
|
|
if (this.#options.defer ?? true) {
|
|
if (!this.#queue) {
|
|
this.#queue = []
|
|
queueMicrotask(() => {
|
|
this.dispatchEvent(new ChangeEvent(...this.#queue))
|
|
this.#queue = undefined
|
|
})
|
|
}
|
|
this.#queue.push([prop, value])
|
|
this.#target[prop] = value
|
|
} else {
|
|
this.#target[prop] = value
|
|
this.dispatchEvent(new ChangeEvent([prop, value]))
|
|
}
|
|
}
|
|
}
|
|
|
|
export default State
|