Compare commits

...

3 commits

2 changed files with 14 additions and 24 deletions

View file

@ -38,7 +38,7 @@ export class ChangedEvent extends Event {
/** @param {Change[]} changes */ /** @param {Change[]} changes */
constructor(...changes) { constructor(...changes) {
super('change') super('changed')
this.changes = changes this.changes = changes
} }
@ -134,6 +134,7 @@ export class Observable extends EventTarget {
enqueue(property, from, to, mutation=false) { enqueue(property, from, to, mutation=false) {
const change = {property, from, to, mutation} const change = {property, from, to, mutation}
if (!this.dispatchEvent(new ChangeEvent(change))) return false if (!this.dispatchEvent(new ChangeEvent(change))) return false
if (!this.synchronous) { if (!this.synchronous) {
if (!this.#queue) { if (!this.#queue) {
this.#queue = [] this.#queue = []
@ -260,9 +261,14 @@ export class ObservableValue extends Observable {
} }
} }
/** @param {Change[]} changes */ /**
emit(...changes) { * @param {(value: any) => any} func
this.dispatchEvent(new ChangedEvent(...changes)) */
compose(func) {
return new Composition(func, {}, this)
}
proxy(methods) {
} }
} }
@ -365,34 +371,17 @@ class Composition extends ObservableValue {
const ref = new WeakRef(this) const ref = new WeakRef(this)
obesrvables.forEach(state => { obesrvables.forEach(state => {
state.addEventListener("change", () => { state.addEventListener("changed", () => {
ref.deref()?.scheduleUpdate() ref.deref()?.update()
}, {signal: abortController.signal}) }, {signal: abortController.signal})
}) })
this.update() this.update()
} }
#microtaskQueued = false
scheduleUpdate() {
if (this.synchronous) {
this.update()
} else {
if (!this.#microtaskQueued) {
queueMicrotask(() => {
this.#microtaskQueued = false
this.update()
})
this.#microtaskQueued = true
}
}
}
update() { update() {
const value = this.#func(...this.#states.map(state => state.value)) const value = this.#func(...this.#states.map(state => state.value))
const change = {property: "value", from: this.value, to: value}
this.value = value this.value = value
this.emit(change)
} }
} }

View file

@ -204,7 +204,7 @@ export class DomRenderer extends Renderer {
if (observable.value instanceof DocumentFragment) { if (observable.value instanceof DocumentFragment) {
throw "Failed to create reactive element: Document fragments cannot be replaced dynamically" throw "Failed to create reactive element: Document fragments cannot be replaced dynamically"
} }
const element = this.toElement(observable.value) const element = this.toElement(observable.value) || document.createComment("Reactive element Placeholder")
untilDeathDoThemPart(element, observable) untilDeathDoThemPart(element, observable)
let ref = new WeakRef(element) let ref = new WeakRef(element)
@ -217,6 +217,7 @@ export class DomRenderer extends Renderer {
if (element?.dispatchEvent(new BeforeReplaceEvent(next))) { if (element?.dispatchEvent(new BeforeReplaceEvent(next))) {
element.replaceWith(next) element.replaceWith(next)
next.dispatchEvent(new ReplacedEvent(element)) next.dispatchEvent(new ReplacedEvent(element))
untilDeathDoThemPart(next, observable)
element.dispatchEvent(new AfterReplaceEvent(next)) element.dispatchEvent(new AfterReplaceEvent(next))
ref = new WeakRef(next) ref = new WeakRef(next)
} }