UNPKG

@pionjs/pion

Version:

Hooks for web components

67 lines (66 loc) 1.89 kB
import { hook, Hook } from "./hook"; import { contextEvent } from "./symbols"; import { setEffects } from "./use-effect"; const getEmitter = (host) => { if (host instanceof Element) return host; return host.startNode || host.endNode || host.parentNode; }; /** * @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.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 }; const emitter = getEmitter(this.state.host); emitter.dispatchEvent(new CustomEvent(contextEvent, { detail, // carrier bubbles: true, // to bubble up in tree cancelable: true, // to be able to cancel 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 };