84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
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();
|
|
};
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @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);
|
|
}
|
|
}
|