UNPKG

3.07 kBJavaScriptView Raw
1import options from './options';
2
3/**
4 * Create an virtual node (used for JSX)
5 * @param {import('./internal').VNode["type"]} type The node name or Component
6 * constructor for this virtual node
7 * @param {object | null | undefined} [props] The properties of the virtual node
8 * @param {Array<import('.').ComponentChildren>} [children] The children of the virtual node
9 * @returns {import('./internal').VNode}
10 */
11export function createElement(type, props, children) {
12 let normalizedProps = {},
13 key,
14 ref,
15 i;
16 for (i in props) {
17 if (i == 'key') key = props[i];
18 else if (i == 'ref') ref = props[i];
19 else normalizedProps[i] = props[i];
20 }
21
22 if (arguments.length > 3) {
23 children = [children];
24 // https://github.com/preactjs/preact/issues/1916
25 for (i = 3; i < arguments.length; i++) {
26 children.push(arguments[i]);
27 }
28 }
29 if (children != null) {
30 normalizedProps.children = children;
31 }
32
33 // If a Component VNode, check for and apply defaultProps
34 // Note: type may be undefined in development, must never error here.
35 if (typeof type == 'function' && type.defaultProps != null) {
36 for (i in type.defaultProps) {
37 if (normalizedProps[i] === undefined) {
38 normalizedProps[i] = type.defaultProps[i];
39 }
40 }
41 }
42
43 return createVNode(type, normalizedProps, key, ref, null);
44}
45
46/**
47 * Create a VNode (used internally by Preact)
48 * @param {import('./internal').VNode["type"]} type The node name or Component
49 * Constructor for this virtual node
50 * @param {object | string | number | null} props The properties of this virtual node.
51 * If this virtual node represents a text node, this is the text of the node (string or number).
52 * @param {string | number | null} key The key for this virtual node, used when
53 * diffing it against its children
54 * @param {import('./internal').VNode["ref"]} ref The ref property that will
55 * receive a reference to its created child
56 * @returns {import('./internal').VNode}
57 */
58export function createVNode(type, props, key, ref, original) {
59 // V8 seems to be better at detecting type shapes if the object is allocated from the same call site
60 // Do not inline into createElement and coerceToVNode!
61 const vnode = {
62 type,
63 props,
64 key,
65 ref,
66 _children: null,
67 _parent: null,
68 _depth: 0,
69 _dom: null,
70 // _nextDom must be initialized to undefined b/c it will eventually
71 // be set to dom.nextSibling which can return `null` and it is important
72 // to be able to distinguish between an uninitialized _nextDom and
73 // a _nextDom that has been set to `null`
74 _nextDom: undefined,
75 _component: null,
76 constructor: undefined,
77 _original: original
78 };
79
80 if (original == null) vnode._original = vnode;
81 if (options.vnode != null) options.vnode(vnode);
82
83 return vnode;
84}
85
86export function createRef() {
87 return { current: null };
88}
89
90export function Fragment(props) {
91 return props.children;
92}
93
94/**
95 * Check if a the argument is a valid Preact VNode.
96 * @param {*} vnode
97 * @returns {vnode is import('./internal').VNode}
98 */
99export const isValidElement = vnode =>
100 vnode != null && vnode.constructor === undefined;