1 | import { slice } from './util';
|
2 | import options from './options';
|
3 |
|
4 | let 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 | */
|
14 | export 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 | */
|
55 | export 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 |
|
84 | export function createRef() {
|
85 | return { current: null };
|
86 | }
|
87 |
|
88 | export 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 | */
|
97 | export const isValidElement = vnode =>
|
98 | vnode != null && vnode.constructor === undefined;
|