@pionjs/pion
Version:
Hooks for web components
59 lines (58 loc) • 1.85 kB
JavaScript
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.updateProp(initialValue);
}
update(ignored, ignored2) {
return [this.state.host[this.property], this.updater];
}
updater(value) {
const previousValue = this.state.host[this.property];
if (typeof value === "function") {
const updaterFn = value;
value = updaterFn(previousValue);
}
if (Object.is(previousValue, value)) {
return;
}
this.updateProp(value);
}
updateProp(value) {
const ev = this.notify(value);
if (ev.defaultPrevented)
return;
this.state.host[this.property] = value;
}
notify(value) {
const ev = new CustomEvent(this.eventName, {
detail: { value, path: this.property },
cancelable: true,
});
this.state.host.dispatchEvent(ev);
return ev;
}
});
export const lift = (setter) => (ev) => {
ev.preventDefault();
setter(ev.detail.value);
};