haunted
Version:
Hooks for web components
64 lines (63 loc) • 1.75 kB
JavaScript
import { hook, Hook } from "./hook";
import { contextEvent } from "./symbols";
import { setEffects } from "./use-effect";
/**
* @function
* @template T
* @param {Context<T>} context
* @return {T}
*/
const useContext = hook(class extends Hook {
Context;
value;
_ranEffect;
_unsubscribe;
constructor(id, state, _) {
super(id, state);
this._updater = this._updater.bind(this);
this._ranEffect = false;
this._unsubscribe = null;
setEffects(state, this);
}
update(Context) {
if (this.state.virtual) {
throw new Error("can't be used with virtual components");
}
if (this.Context !== Context) {
this._subscribe(Context);
this.Context = Context;
}
return this.value;
}
call() {
if (!this._ranEffect) {
this._ranEffect = true;
if (this._unsubscribe)
this._unsubscribe();
this._subscribe(this.Context);
this.state.update();
}
}
_updater(value) {
this.value = value;
this.state.update();
}
_subscribe(Context) {
const detail = { Context, callback: this._updater };
this.state.host.dispatchEvent(new CustomEvent(contextEvent, {
detail,
bubbles: true,
cancelable: true,
composed: true, // to pass ShadowDOM boundaries
}));
const { unsubscribe = null, value } = detail;
this.value = unsubscribe ? value : Context.defaultValue;
this._unsubscribe = unsubscribe;
}
teardown() {
if (this._unsubscribe) {
this._unsubscribe();
}
}
});
export { useContext };