diff options
Diffstat (limited to 'packages/web-util/src/components/utils.ts')
-rw-r--r-- | packages/web-util/src/components/utils.ts | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/packages/web-util/src/components/utils.ts b/packages/web-util/src/components/utils.ts new file mode 100644 index 000000000..75c3fc0fe --- /dev/null +++ b/packages/web-util/src/components/utils.ts @@ -0,0 +1,111 @@ +import { createElement, VNode } from "preact"; + +export type StateFunc<S> = (p: S) => VNode; + +export type StateViewMap<StateType extends { status: string }> = { + [S in StateType as S["status"]]: StateFunc<S>; +}; + +export type RecursiveState<S extends object> = S | (() => RecursiveState<S>); + +export function compose<SType extends { status: string }, PType>( + hook: (p: PType) => RecursiveState<SType>, + viewMap: StateViewMap<SType>, +): (p: PType) => VNode { + + function withHook(stateHook: () => RecursiveState<SType>): () => VNode { + function ComposedComponent(): VNode { + const state = stateHook(); + + if (typeof state === "function") { + const subComponent = withHook(state); + return createElement(subComponent, {}); + } + + const statusName = state.status as unknown as SType["status"]; + const viewComponent = viewMap[statusName] as unknown as StateFunc<SType>; + return createElement(viewComponent, state); + } + + return ComposedComponent; + } + + return (p: PType) => { + const h = withHook(() => hook(p)); + return h(); + }; +} + +export function recursive<PType>( + hook: (p: PType) => RecursiveState<VNode>, +): (p: PType) => VNode { + + function withHook(stateHook: () => RecursiveState<VNode>): () => VNode { + function ComposedComponent(): VNode { + const state = stateHook(); + + if (typeof state === "function") { + const subComponent = withHook(state); + return createElement(subComponent, {}); + } + + return state; + } + + return ComposedComponent; + } + + return (p: PType) => { + const h = withHook(() => hook(p)); + return h(); + }; +} + + + +/** + * + * @param obj VNode + * @returns + */ +export function saveVNodeForInspection<T>(obj: T): T { + // @ts-ignore + window["showVNodeInfo"] = function showVNodeInfo() { + inspect(obj); + }; + return obj; +} +function inspect(obj: any) { + if (!obj) return; + if (obj.__c && obj.__c.__H) { + const componentName = obj.__c.constructor.name; + const hookState = obj.__c.__H; + const stateList = hookState.__ as Array<any>; + console.log("==============", componentName); + stateList.forEach((hook) => { + const { __: value, c: context, __h: factory, __H: args } = hook; + if (typeof context !== "undefined") { + const { __c: contextId } = context; + console.log("context:", contextId, hook); + } else if (typeof factory === "function") { + console.log("memo:", value, "deps:", args); + } else if (typeof value === "function") { + const effectName = value.name; + console.log("effect:", effectName, "deps:", args); + } else if (typeof value.current !== "undefined") { + const ref = value.current; + console.log("ref:", ref instanceof Element ? ref.outerHTML : ref); + } else if (value instanceof Array) { + console.log("state:", value[0]); + } else { + console.log(hook); + } + }); + } + const children = obj.__k; + if (children instanceof Array) { + children.forEach((e) => inspect(e)); + } else { + inspect(children); + } +} |