Cache forwarded states to avoid duplication
This commit is contained in:
parent
e38d556531
commit
e80801b639
1 changed files with 35 additions and 1 deletions
36
state.js
36
state.js
|
@ -38,6 +38,7 @@ export class State extends EventTarget {
|
|||
#target
|
||||
#options
|
||||
#queue
|
||||
#forwardCache
|
||||
|
||||
constructor(target={}, options={}) {
|
||||
super()
|
||||
|
@ -86,7 +87,17 @@ export class State extends EventTarget {
|
|||
}
|
||||
|
||||
forward(property="value", fallback) {
|
||||
return new ForwardState(this, property, fallback)
|
||||
if (!this.#forwardCache) this.#forwardCache = new Map()
|
||||
const cached = this.#forwardCache.get(property).deref()
|
||||
if (cached) {
|
||||
return cached
|
||||
} else {
|
||||
const forwarded = new ForwardState(this, property, fallback)
|
||||
ref = new Weakref(forwarded)
|
||||
this.#forwardCache.set(property, ref)
|
||||
forwardFinalizationRegistry.register(forwarded, [this.#forwardCache, property])
|
||||
return forwarded
|
||||
}
|
||||
}
|
||||
|
||||
set(prop, value) {
|
||||
|
@ -98,6 +109,10 @@ export class State extends EventTarget {
|
|||
}
|
||||
}
|
||||
|
||||
const forwardFinalizationRegistry = new FinalizationRegistry(([cache, name]) => {
|
||||
cache.remove(name)
|
||||
})
|
||||
|
||||
export class ForwardState extends EventTarget {
|
||||
#backend
|
||||
#property
|
||||
|
@ -186,4 +201,23 @@ export class StoredState extends State {
|
|||
}
|
||||
}
|
||||
|
||||
const attributeObserver = new MutationObserver(mutations => {
|
||||
for (const {type, target, attributeName: name} of mutations) {
|
||||
if (type == "attributes")
|
||||
target.state.proxy[name] = target.getAttribute(name)
|
||||
}
|
||||
})
|
||||
|
||||
export const component = (generator, name) => {
|
||||
name = name ?? generator.name.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}-${b.toLowerCase()}`)
|
||||
customElements.define(name, class extends HTMLElement{
|
||||
constructor() {
|
||||
super()
|
||||
this.state = new State(Object.fromEntries([...this.attributes].map(attribute => [attribute.name, attribute.value])))
|
||||
attributeObserver.observe(this, {attributes: true})
|
||||
this.replaceChildren(generator(this.state))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default State
|
||||
|
|
Loading…
Reference in a new issue