diff options
Diffstat (limited to 'preact/src/create-element.js')
-rw-r--r-- | preact/src/create-element.js | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/preact/src/create-element.js b/preact/src/create-element.js new file mode 100644 index 0000000..90ee753 --- /dev/null +++ b/preact/src/create-element.js @@ -0,0 +1,97 @@ +import { slice } from './util'; +import options from './options'; + +let vnodeId = 0; + +/** + * Create an virtual node (used for JSX) + * @param {import('./internal').VNode["type"]} type The node name or Component + * constructor for this virtual node + * @param {object | null | undefined} [props] The properties of the virtual node + * @param {Array<import('.').ComponentChildren>} [children] The children of the virtual node + * @returns {import('./internal').VNode} + */ +export function createElement(type, props, children) { + let normalizedProps = {}, + key, + ref, + i; + for (i in props) { + if (i == 'key') key = props[i]; + else if (i == 'ref') ref = props[i]; + else normalizedProps[i] = props[i]; + } + + if (arguments.length > 2) { + normalizedProps.children = + arguments.length > 3 ? slice.call(arguments, 2) : children; + } + + // If a Component VNode, check for and apply defaultProps + // Note: type may be undefined in development, must never error here. + if (typeof type == 'function' && type.defaultProps != null) { + for (i in type.defaultProps) { + if (normalizedProps[i] === undefined) { + normalizedProps[i] = type.defaultProps[i]; + } + } + } + + return createVNode(type, normalizedProps, key, ref, null); +} + +/** + * Create a VNode (used internally by Preact) + * @param {import('./internal').VNode["type"]} type The node name or Component + * Constructor for this virtual node + * @param {object | string | number | null} props The properties of this virtual node. + * If this virtual node represents a text node, this is the text of the node (string or number). + * @param {string | number | null} key The key for this virtual node, used when + * diffing it against its children + * @param {import('./internal').VNode["ref"]} ref The ref property that will + * receive a reference to its created child + * @returns {import('./internal').VNode} + */ +export function createVNode(type, props, key, ref, original) { + // V8 seems to be better at detecting type shapes if the object is allocated from the same call site + // Do not inline into createElement and coerceToVNode! + const vnode = { + type, + props, + key, + ref, + _children: null, + _parent: null, + _depth: 0, + _dom: null, + // _nextDom must be initialized to undefined b/c it will eventually + // be set to dom.nextSibling which can return `null` and it is important + // to be able to distinguish between an uninitialized _nextDom and + // a _nextDom that has been set to `null` + _nextDom: undefined, + _component: null, + _hydrating: null, + constructor: undefined, + _original: original == null ? ++vnodeId : original + }; + + if (options.vnode != null) options.vnode(vnode); + + return vnode; +} + +export function createRef() { + return { current: null }; +} + +export function Fragment(props) { + return props.children; +} + +/** + * Check if a the argument is a valid Preact VNode. + * @param {*} vnode + * @returns {vnode is import('./internal').VNode} + */ +export const isValidElement = vnode => + vnode != null && vnode.constructor === undefined; |