import { find, getValues, IObject, isString } from "@daybrush/utils"; import { Component } from "./Component"; import { CompatElement, ContextProvider, Ref } from "../types"; import { flat } from "../utils"; import { renderProviders } from "../renderProviders"; import { HooksProvider } from "../hooks/hooks"; let hooksIndex = 0; export abstract class Provider implements ContextProvider { public typ = "prov"; /** * Original */ public o: CompatElement | string; /** * Base */ public b: T; /** * providers */ public _ps: Array> = []; /** * Forwarded Ref */ public fr?: Ref; /** * Contexts */ public _cs: Record = {}; /** * Whether to hydrate */ public _hyd: Node[] | null = null; /** * is self render */ public _sel = false; constructor( /** * Type */ public t: any, /** * Depth */ public d: number, /** * Key */ public k: string, /** * index */ public i: number, /** * Container */ public c?: Provider | null, /** * Ref */ public ref?: Ref, /** * Props */ public ps: IObject = {}, ) { } /** * Render */ public abstract r(hooks: Function[], contextValues: Record, prevProps: any, nextState?: any); /** * Unmount */ public abstract un(); /** * Should update */ public s(nextProps: any, nextState: any): boolean; public s() { return true; } /** * Update */ public u( hooks: Function[], contexts: Record, nextElement: CompatElement | string, nextState?: any, isForceUpdate?: boolean, ) { const self = this; const currentDepth = self.d; const scheduledContexts = getValues(contexts).filter(context => { return context.$_req; }); const scheduledSubs = flat(scheduledContexts.map(context => context.$_subs)) as Provider[]; const isContextUpdate = find(scheduledSubs, provider => { return provider.d === currentDepth; }); if ( self.b && !isString(nextElement) && !isForceUpdate && !self.s(nextElement.props, nextState) && !isContextUpdate ) { const nextChildSubs = scheduledSubs.reduce((childs, sub) => { const depth = sub.d; if (childs[0]) { if (childs[0].d === depth) { childs.push(sub); } } else if (depth > currentDepth) { childs.push(sub); } return childs; }, [] as Provider[]); nextChildSubs.forEach(child => { // provider.container!, // [provider], // [provider.original], // hooks, // provider._cs, // { ...self.state, ...self.$_state }, // isForceUpdate, renderProviders( child, child._ps, [child.o], hooks, contexts, true, ); }) return false; } self.o = nextElement; self.ss(nextState); // render const prevProps = self.ps; if (!isString(nextElement)) { self.ps = nextElement.props; self.ref = nextElement.ref; } setCurrentInstance(this); self.r(hooks, contexts, self.b ? prevProps : {}, nextState); return true; } public md() { this.rr(); } public ss(nextstate: IObject); public ss() { return; } public ud() { this.rr(); } /** * register refs */ public rr() { const self = this; const ref = self.ref; const fr = self.fr; ref && ref(fr ? fr.current : self.b); } } export function getCurrentInstance(): Provider | HooksProvider | null { return (Object as any).__CROACT_CURRENT_INSTNACE__; } export function getHooksIndex() { return hooksIndex; } export function setHooksInex(nextHooksIndex: number) { hooksIndex = nextHooksIndex; } export function setCurrentInstance(provider: Provider | HooksProvider | null) { (Object as any).__CROACT_CURRENT_INSTNACE__ = provider; hooksIndex = 0; return provider; }