UNPKG

2.86 kBPlain TextView Raw
1/* eslint-disable @typescript-eslint/no-namespace, import/export */
2import { Key, vnode, VNode, VNodeData } from "./vnode";
3import { h, ArrayOrElement } from "./h";
4
5// See https://www.typescriptlang.org/docs/handbook/jsx.html#type-checking
6namespace JSXInternal {
7 export type Element = VNode;
8 export interface IntrinsicElements {
9 [elemName: string]: VNodeData;
10 }
11}
12
13// for conditional rendering we support boolean child element e.g cond && <tag />
14export type JsxVNodeChild =
15 | VNode
16 | string
17 | number
18 | boolean
19 | undefined
20 | null;
21export type JsxVNodeChildren = ArrayOrElement<JsxVNodeChild>;
22
23export type FunctionComponent = (
24 props: { [prop: string]: any } | null,
25 children?: VNode[]
26) => VNode;
27
28export function Fragment(
29 data: { key?: Key } | null,
30 ...children: JsxVNodeChildren[]
31): VNode {
32 const flatChildren = flattenAndFilter(children, []);
33
34 if (
35 flatChildren.length === 1 &&
36 !flatChildren[0].sel &&
37 flatChildren[0].text
38 ) {
39 // only child is a simple text node, pass as text for a simpler vtree
40 return vnode(
41 undefined,
42 undefined,
43 undefined,
44 flatChildren[0].text,
45 undefined
46 );
47 } else {
48 return vnode(undefined, data ?? {}, flatChildren, undefined, undefined);
49 }
50}
51
52function flattenAndFilter(
53 children: JsxVNodeChildren[],
54 flattened: VNode[]
55): VNode[] {
56 for (const child of children) {
57 // filter out falsey children, except 0 since zero can be a valid value e.g inside a chart
58 if (
59 child !== undefined &&
60 child !== null &&
61 child !== false &&
62 child !== ""
63 ) {
64 if (Array.isArray(child)) {
65 flattenAndFilter(child, flattened);
66 } else if (
67 typeof child === "string" ||
68 typeof child === "number" ||
69 typeof child === "boolean"
70 ) {
71 flattened.push(
72 vnode(undefined, undefined, undefined, String(child), undefined)
73 );
74 } else {
75 flattened.push(child);
76 }
77 }
78 }
79 return flattened;
80}
81
82/**
83 * jsx/tsx compatible factory function
84 * see: https://www.typescriptlang.org/docs/handbook/jsx.html#factory-functions
85 */
86export function jsx(
87 tag: string | FunctionComponent,
88 data: VNodeData | null,
89 ...children: JsxVNodeChildren[]
90): VNode {
91 const flatChildren = flattenAndFilter(children, []);
92 if (typeof tag === "function") {
93 // tag is a function component
94 return tag(data, flatChildren);
95 } else {
96 if (
97 flatChildren.length === 1 &&
98 !flatChildren[0].sel &&
99 flatChildren[0].text
100 ) {
101 // only child is a simple text node, pass as text for a simpler vtree
102 return h(tag, data, flatChildren[0].text);
103 } else {
104 return h(tag, data, flatChildren);
105 }
106 }
107}
108
109export namespace jsx {
110 export import JSX = JSXInternal; // eslint-disable-line @typescript-eslint/no-unused-vars
111}