UNPKG

@pionjs/pion

Version:

Hooks for web components

61 lines (60 loc) 2.1 kB
import { hook, Hook } from "./hook"; const UPPER = /([A-Z])/gu; export const useProperty = hook(class extends Hook { property; eventName; constructor(id, state, property, initialValue) { super(id, state); if (this.state.virtual) { throw new Error("Can't be used with virtual components."); } this.updater = this.updater.bind(this); this.property = property; this.eventName = property.replace(UPPER, "-$1").toLowerCase() + "-changed"; // set the initial value only if it was not already set by the parent if (this.state.host[this.property] != null) return; if (typeof initialValue === "function") { const initFn = initialValue; initialValue = initFn(); } if (initialValue == null) return; this.updater(initialValue, true); } update(ignored, ignored2) { return [this.state.host[this.property], this.updater]; } resolve(valueOrUpdater) { const previousValue = this.state.host[this.property]; const updater = typeof valueOrUpdater === "function" ? valueOrUpdater : undefined; const value = updater ? updater(previousValue) : valueOrUpdater; return [previousValue, value, updater]; } notify(value, updater) { const ev = new CustomEvent(this.eventName, { detail: { value, updater, path: this.property }, cancelable: true, }); this.state.host.dispatchEvent(ev); return ev; } updater(valueOrUpdater, isInit = false) { const [previousValue, value, updater] = this.resolve(valueOrUpdater); const ev = this.notify(value, updater); if (!isInit && ev.defaultPrevented) return; if (Object.is(previousValue, value)) return; this.state.host[this.property] = value; } }); export const lift = (setter) => (ev) => { ev.preventDefault(); setter(ev.detail.updater ?? ev.detail.value); };