-
Notifications
You must be signed in to change notification settings - Fork 1
/
constructs-jsx.tsx
77 lines (60 loc) · 2.05 KB
/
constructs-jsx.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { Construct, IConstruct } from "constructs";
export function Fragment({ children }: { children: JSX.Element[] }) {
return children;
}
interface RefObject<T> {
readonly current: T | null;
}
export const createRef = useRef;
export function useRef<T>(initialValue: T | null): RefObject<T> {
return { current: initialValue };
}
const effectQueue: Array<() => void> = [];
export function useLayoutEffect(effect: () => void) {
effectQueue.push(effect);
}
function isConstruct(type: unknown): type is typeof Construct {
return Construct.isPrototypeOf(type as IConstruct) || type === Construct;
}
export function render(element: JSX.Element, parentConstruct: Construct) {
return visit(element, parentConstruct);
function visit(
element: JSX.Element | JSX.Element[],
parentConstruct: Construct,
index = 0
): Construct {
if (Array.isArray(element)) {
element.forEach((child, index) => visit(child, parentConstruct, index));
return parentConstruct;
}
if (element.type === Fragment) {
return visit(element.props.children, parentConstruct);
}
if (isConstruct(element.type)) {
const { key, props, type } = element;
const { ref, children, ...options } = props;
const construct = new type(
parentConstruct,
key ?? `${type.name}-${index}`,
options
);
if (ref) ref.current = construct;
if (children) visit(children, construct);
return parentConstruct;
}
if (element.type instanceof Function) {
const { type, props, key } = element;
const beforeEffectsCount = effectQueue.length;
const newElement = type({ ...props, key });
const afterEffectsCount = effectQueue.length;
const iterable = { length: afterEffectsCount - beforeEffectsCount };
const construct = visit(newElement, parentConstruct);
Array.from(iterable, () => {
const effect = effectQueue.pop();
if (effect) effect();
});
return construct;
}
throw new Error(`${element?.type ?? element} is not supported`);
}
}