import {BaseElement} from "../element.js" export function attributes( element: BaseElement, spec: A, ) { Attributes.on_change(element, () => element.requestUpdate()) return Attributes.proxy(element, spec) } export namespace Attributes { type HardValue = ( | typeof String | typeof Number | typeof Boolean ) type SoftenValue = ( H extends typeof String ? string | undefined : H extends typeof Number ? number | undefined : H extends typeof Boolean ? boolean : never ) export type Spec = { [key: string]: HardValue } export type SoftenSpec = { [P in keyof A]: SoftenValue } export const proxy = ( element: HTMLElement, spec: A, ) => new Proxy(spec, { get: (_target, name: string) => { const type = spec[name] const raw = element.getAttribute(name) switch (type) { case String: return raw ?? undefined case Number: return raw !== null ? Number(raw) : undefined case Boolean: return raw !== null default: throw new Error(`invalid attribute type for "${name}"`) } }, set: (_target, name: string, value: any) => { const type = spec[name] switch (type) { case String: { element.setAttribute(name, value) return true } case Number: { element.setAttribute(name, value.toString()) return true } case Boolean: { if (value) element.setAttribute(name, "") else element.removeAttribute(name) return true } default: throw new Error(`invalid attribute type for "${name}"`) } }, }) as any as SoftenSpec export function on_change(element: HTMLElement, handle_change: () => void) { const observer = new MutationObserver(handle_change) observer.observe(element, {attributes: true}) return () => observer.disconnect() } }