summaryrefslogtreecommitdiff
path: root/preact/src/create-element.js
diff options
context:
space:
mode:
Diffstat (limited to 'preact/src/create-element.js')
-rw-r--r--preact/src/create-element.js97
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;