UNPKG

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