Add nested state change forwarding
This commit is contained in:
parent
37948987b0
commit
cdc56f5848
1 changed files with 46 additions and 5 deletions
47
state.js
47
state.js
|
@ -14,6 +14,8 @@ export class ChangeEvent extends Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SimpleState extends EventTarget {}
|
||||||
|
|
||||||
export class MapStorage extends Storage {
|
export class MapStorage extends Storage {
|
||||||
#map = new Map()
|
#map = new Map()
|
||||||
key(index) {
|
key(index) {
|
||||||
|
@ -36,20 +38,36 @@ export class MapStorage extends Storage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class State extends EventTarget {
|
export class State extends SimpleState {
|
||||||
#target
|
#target
|
||||||
#options
|
#options
|
||||||
#queue
|
#queue
|
||||||
#forwardCache
|
#forwardCache
|
||||||
|
#abortController
|
||||||
|
#nested = new Map()
|
||||||
|
#weakRef = new WeakRef(this)
|
||||||
|
|
||||||
|
static isState(object) { return SimpleState.prototype.isPrototypeOf(object) }
|
||||||
|
|
||||||
constructor(target={}, options={}) {
|
constructor(target={}, options={}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.#abortController = new AbortController
|
||||||
|
abortRegistry.register(this, this.#abortController)
|
||||||
|
|
||||||
this.#options = options
|
this.#options = options
|
||||||
this.#target = target
|
this.#target = target
|
||||||
this.proxy = new Proxy(target, {
|
this.proxy = new Proxy(target, {
|
||||||
set: (_target, prop, value) => {
|
set: (_target, prop, value) => {
|
||||||
|
const old = this.get(prop)
|
||||||
|
if (old !== value) {
|
||||||
this.emit(prop, value)
|
this.emit(prop, value)
|
||||||
|
if (this.#options.deep !== false) {
|
||||||
|
if (State.isState(old)) this.disown(prop, old)
|
||||||
|
if (State.isState(value)) this.adopt(prop, value)
|
||||||
|
}
|
||||||
this.set(prop, value)
|
this.set(prop, value)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
get: (_target, prop) => this.get(prop),
|
get: (_target, prop) => this.get(prop),
|
||||||
|
@ -72,6 +90,29 @@ export class State extends EventTarget {
|
||||||
set value(value) { this.proxy.value = value }
|
set value(value) { this.proxy.value = value }
|
||||||
get value() { return this.proxy.value }
|
get value() { return this.proxy.value }
|
||||||
|
|
||||||
|
adopt(prop, state) {
|
||||||
|
let handlers = this.#nested.get(state)
|
||||||
|
if (!handlers) {
|
||||||
|
// Actual adoption
|
||||||
|
handlers = new Map()
|
||||||
|
this.#nested.set(state, handlers)
|
||||||
|
}
|
||||||
|
const ref = this.#weakRef
|
||||||
|
const handler = () => ref.deref()?.emit(prop, state)
|
||||||
|
|
||||||
|
handlers.set(prop, handler)
|
||||||
|
state.addEventListener("change", handler, {signal: this.#abortController.signal})
|
||||||
|
}
|
||||||
|
disown(prop, state) {
|
||||||
|
const handlers = this.#nested.get(state)
|
||||||
|
const handler = handlers.get(prop)
|
||||||
|
state.removeEventListener("change", handler)
|
||||||
|
handlers.delete(prop)
|
||||||
|
if (handlers.size == 0) {
|
||||||
|
this.#nested.delete(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Anounces that a prop has changed
|
// Anounces that a prop has changed
|
||||||
emit(prop, value) {
|
emit(prop, value) {
|
||||||
if (this.#options.defer ?? true) {
|
if (this.#options.defer ?? true) {
|
||||||
|
@ -115,7 +156,7 @@ const forwardFinalizationRegistry = new FinalizationRegistry(([cache, name]) =>
|
||||||
cache.remove(name)
|
cache.remove(name)
|
||||||
})
|
})
|
||||||
|
|
||||||
export class ForwardState extends EventTarget {
|
export class ForwardState extends SimpleState {
|
||||||
#backend
|
#backend
|
||||||
#property
|
#property
|
||||||
#fallback
|
#fallback
|
||||||
|
@ -235,7 +276,7 @@ export const component = (generator, name) => {
|
||||||
return Element;
|
return Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComposedState extends EventTarget {
|
class ComposedState extends SimpleState {
|
||||||
#func
|
#func
|
||||||
#states
|
#states
|
||||||
#options
|
#options
|
||||||
|
|
Loading…
Reference in a new issue