Compare commits

...

5 Commits

Author SHA1 Message Date
Talia 5a29b0e662 Make `handle` return a value just in case it is desired 2024-01-15 11:50:27 +01:00
Talia 0e6eee28fd Make DOMState API more generic
The old interface was too specific to the way domLense works, by
assuming the value to be an array that gets mutated elsewhere (or a
proxy that behaves like one)
2024-01-15 11:48:52 +01:00
Talia eb75dc531a Remove exports from state.js 2024-01-15 11:03:11 +01:00
Talia 3b3e6467c8 Refactor exports
Export rules:
* All default exports as named exports
* Default export wherever it makes sense
2024-01-11 15:44:11 +01:00
Talia 7be7cf0210
Change DOMState value to last static value 2024-01-10 22:47:30 +01:00
3 changed files with 31 additions and 20 deletions

View File

@ -14,7 +14,7 @@ class ChildObserver extends MutationObserver {
const childObserver = new ChildObserver()
const lense = (methods, extra) => {
export const lense = (methods, extra) => {
if (extra) return lense(extra)(methods)
const traps = {

View File

@ -10,6 +10,7 @@ or
html.ul([1, 2, 3, 4, 5].map(x => html.li(x)), {class: "numbers"})
*/
// Keep a referee alive until a referrer is collected
const weakReferences = new WeakMap()
const untilDeathDoThemPart = (referrer, reference) => {
if (!weakReferences.has(referrer)) {
@ -184,11 +185,12 @@ const nameSpacedProxy = (options={}) => new Proxy(Window, {
export const html = nameSpacedProxy({nameFilter: name => name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()})
export const svg = nameSpacedProxy({xmlns: "http://www.w3.org/2000/svg"})
export default html
// Other utility exports
// Wraps an event handler in a function that calls preventDefault on the event
export const handle = fn => event => { fn(event); event.preventDefault() }
export const handle = fn => event => { event.preventDefault(); return fn(event) }
// Wraps a list of elements in a document fragment
export const fragment = (...elements) => {

View File

@ -1,4 +1,4 @@
export const abortRegistry = new FinalizationRegistry(controller => controller.abort())
const abortRegistry = new FinalizationRegistry(controller => controller.abort())
const camelToKebab = string => string.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}-${b.toLowerCase()}`)
const kebabToCamel = string => string.replace(/([a-z])-([a-z])/g, (_, a, b) => a+b.toUpperCase())
@ -17,7 +17,7 @@ export class ChangeEvent extends Event {
}
}
class SimpleState extends EventTarget {}
export class SimpleState extends EventTarget {}
export class MapStorage extends Storage {
#map = new Map()
@ -189,7 +189,7 @@ export class ForwardState extends SimpleState {
set value(value) { this.#backend.proxy[this.#property] = value }
}
export class StorageChangeEvent extends Event {
class StorageChangeEvent extends Event {
constructor(storage, key, value, targetState) {
super("storagechange")
this.storageArea = storage
@ -345,36 +345,45 @@ const mutationObserver = new MutationObserver(mutations => {
})
export class DOMState extends SimpleState {
#target
#defer
#getValue
#equal
#old
#options
#changedValue = false
constructor(target, value, options) {
constructor(target, options) {
super()
this.#options = options
this.#old = [...value]
this.value = value
this.#defer = options.defer ?? false
this.#target = target
this.#getValue = options.get ?? (target => target.value)
this.#equal = options.equal ?? ((a, b) => a===b)
this.#old = this.#getValue(target)
const controller = new AbortController()
target.addEventListener(eventName, event=>{this.update(event)}, {signal: controller.signal})
abortRegistry.register(this, controller)
mutationObserver.observe(target, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
})
target.addEventListener(eventName, event=>{this.update(event)}, {signal: controller.signal})
abortRegistry.register(this, controller)
}
get value() { return this.#old }
update() {
const current = [...this.value]
if (current.length === this.#old.length) {
for (const idx in current) {
if (current[idx] !== this.#old[idx]) break
}
return
}
const current = this.#getValue(this.#target)
if (this.#equal(this.#old, current)) return
this.#old = current
if (this.#options?.defer) {
if (this.#defer) {
if (!this.#changedValue) {
queueMicrotask(() => {
this.#changedValue = false