summaryrefslogtreecommitdiff
path: root/preact/src
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-08-23 16:46:06 -0300
committerSebastian <sebasjm@gmail.com>2021-08-23 16:48:30 -0300
commit38acabfa6089ab8ac469c12b5f55022fb96935e5 (patch)
tree453dbf70000cc5e338b06201af1eaca8343f8f73 /preact/src
parentf26125e039143b92dc0d84e7775f508ab0cdcaa8 (diff)
downloadnode-vendor-master.tar.gz
node-vendor-master.tar.bz2
node-vendor-master.zip
added web vendorsHEADmaster
Diffstat (limited to 'preact/src')
-rw-r--r--preact/src/cjs.js3
-rw-r--r--preact/src/clone-element.js34
-rw-r--r--preact/src/component.js225
-rw-r--r--preact/src/constants.js3
-rw-r--r--preact/src/create-context.js68
-rw-r--r--preact/src/create-element.js97
-rw-r--r--preact/src/diff/catch-error.js38
-rw-r--r--preact/src/diff/children.js347
-rw-r--r--preact/src/diff/index.js514
-rw-r--r--preact/src/diff/props.js158
-rw-r--r--preact/src/index.d.ts310
-rw-r--r--preact/src/index.js13
-rw-r--r--preact/src/internal.d.ts146
-rw-r--r--preact/src/jsx.d.ts974
-rw-r--r--preact/src/options.js16
-rw-r--r--preact/src/render.js75
-rw-r--r--preact/src/util.js27
17 files changed, 3048 insertions, 0 deletions
diff --git a/preact/src/cjs.js b/preact/src/cjs.js
new file mode 100644
index 0000000..b4721b1
--- /dev/null
+++ b/preact/src/cjs.js
@@ -0,0 +1,3 @@
+import * as preact from './index.js';
+if (typeof module < 'u') module.exports = preact;
+else self.preact = preact;
diff --git a/preact/src/clone-element.js b/preact/src/clone-element.js
new file mode 100644
index 0000000..4cff226
--- /dev/null
+++ b/preact/src/clone-element.js
@@ -0,0 +1,34 @@
+import { assign, slice } from './util';
+import { createVNode } from './create-element';
+
+/**
+ * Clones the given VNode, optionally adding attributes/props and replacing its children.
+ * @param {import('./internal').VNode} vnode The virtual DOM element to clone
+ * @param {object} props Attributes/props to add when cloning
+ * @param {Array<import('./internal').ComponentChildren>} rest Any additional arguments will be used as replacement children.
+ * @returns {import('./internal').VNode}
+ */
+export function cloneElement(vnode, props, children) {
+ let normalizedProps = assign({}, vnode.props),
+ 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;
+ }
+
+ return createVNode(
+ vnode.type,
+ normalizedProps,
+ key || vnode.key,
+ ref || vnode.ref,
+ null
+ );
+}
diff --git a/preact/src/component.js b/preact/src/component.js
new file mode 100644
index 0000000..c2043af
--- /dev/null
+++ b/preact/src/component.js
@@ -0,0 +1,225 @@
+import { assign } from './util';
+import { diff, commitRoot } from './diff/index';
+import options from './options';
+import { Fragment } from './create-element';
+
+/**
+ * Base Component class. Provides `setState()` and `forceUpdate()`, which
+ * trigger rendering
+ * @param {object} props The initial component props
+ * @param {object} context The initial context from parent components'
+ * getChildContext
+ */
+export function Component(props, context) {
+ this.props = props;
+ this.context = context;
+}
+
+/**
+ * Update component state and schedule a re-render.
+ * @this {import('./internal').Component}
+ * @param {object | ((s: object, p: object) => object)} update A hash of state
+ * properties to update with new values or a function that given the current
+ * state and props returns a new partial state
+ * @param {() => void} [callback] A function to be called once component state is
+ * updated
+ */
+Component.prototype.setState = function(update, callback) {
+ // only clone state when copying to nextState the first time.
+ let s;
+ if (this._nextState != null && this._nextState !== this.state) {
+ s = this._nextState;
+ } else {
+ s = this._nextState = assign({}, this.state);
+ }
+
+ if (typeof update == 'function') {
+ // Some libraries like `immer` mark the current state as readonly,
+ // preventing us from mutating it, so we need to clone it. See #2716
+ update = update(assign({}, s), this.props);
+ }
+
+ if (update) {
+ assign(s, update);
+ }
+
+ // Skip update if updater function returned null
+ if (update == null) return;
+
+ if (this._vnode) {
+ if (callback) this._renderCallbacks.push(callback);
+ enqueueRender(this);
+ }
+};
+
+/**
+ * Immediately perform a synchronous re-render of the component
+ * @this {import('./internal').Component}
+ * @param {() => void} [callback] A function to be called after component is
+ * re-rendered
+ */
+Component.prototype.forceUpdate = function(callback) {
+ if (this._vnode) {
+ // Set render mode so that we can differentiate where the render request
+ // is coming from. We need this because forceUpdate should never call
+ // shouldComponentUpdate
+ this._force = true;
+ if (callback) this._renderCallbacks.push(callback);
+ enqueueRender(this);
+ }
+};
+
+/**
+ * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
+ * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
+ * @param {object} props Props (eg: JSX attributes) received from parent
+ * element/component
+ * @param {object} state The component's current state
+ * @param {object} context Context object, as returned by the nearest
+ * ancestor's `getChildContext()`
+ * @returns {import('./index').ComponentChildren | void}
+ */
+Component.prototype.render = Fragment;
+
+/**
+ * @param {import('./internal').VNode} vnode
+ * @param {number | null} [childIndex]
+ */
+export function getDomSibling(vnode, childIndex) {
+ if (childIndex == null) {
+ // Use childIndex==null as a signal to resume the search from the vnode's sibling
+ return vnode._parent
+ ? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
+ : null;
+ }
+
+ let sibling;
+ for (; childIndex < vnode._children.length; childIndex++) {
+ sibling = vnode._children[childIndex];
+
+ if (sibling != null && sibling._dom != null) {
+ // Since updateParentDomPointers keeps _dom pointer correct,
+ // we can rely on _dom to tell us if this subtree contains a
+ // rendered DOM node, and what the first rendered DOM node is
+ return sibling._dom;
+ }
+ }
+
+ // If we get here, we have not found a DOM node in this vnode's children.
+ // We must resume from this vnode's sibling (in it's parent _children array)
+ // Only climb up and search the parent if we aren't searching through a DOM
+ // VNode (meaning we reached the DOM parent of the original vnode that began
+ // the search)
+ return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
+}
+
+/**
+ * Trigger in-place re-rendering of a component.
+ * @param {import('./internal').Component} component The component to rerender
+ */
+function renderComponent(component) {
+ let vnode = component._vnode,
+ oldDom = vnode._dom,
+ parentDom = component._parentDom;
+
+ if (parentDom) {
+ let commitQueue = [];
+ const oldVNode = assign({}, vnode);
+ oldVNode._original = vnode._original + 1;
+
+ diff(
+ parentDom,
+ vnode,
+ oldVNode,
+ component._globalContext,
+ parentDom.ownerSVGElement !== undefined,
+ vnode._hydrating != null ? [oldDom] : null,
+ commitQueue,
+ oldDom == null ? getDomSibling(vnode) : oldDom,
+ vnode._hydrating
+ );
+ commitRoot(commitQueue, vnode);
+
+ if (vnode._dom != oldDom) {
+ updateParentDomPointers(vnode);
+ }
+ }
+}
+
+/**
+ * @param {import('./internal').VNode} vnode
+ */
+function updateParentDomPointers(vnode) {
+ if ((vnode = vnode._parent) != null && vnode._component != null) {
+ vnode._dom = vnode._component.base = null;
+ for (let i = 0; i < vnode._children.length; i++) {
+ let child = vnode._children[i];
+ if (child != null && child._dom != null) {
+ vnode._dom = vnode._component.base = child._dom;
+ break;
+ }
+ }
+
+ return updateParentDomPointers(vnode);
+ }
+}
+
+/**
+ * The render queue
+ * @type {Array<import('./internal').Component>}
+ */
+let rerenderQueue = [];
+
+/**
+ * Asynchronously schedule a callback
+ * @type {(cb: () => void) => void}
+ */
+/* istanbul ignore next */
+// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
+const defer =
+ typeof Promise == 'function'
+ ? Promise.prototype.then.bind(Promise.resolve())
+ : setTimeout;
+
+/*
+ * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
+ * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
+ * do, and when their effects will be applied. See the links below for some further reading on designing
+ * asynchronous APIs.
+ * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
+ * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
+ */
+
+let prevDebounce;
+
+/**
+ * Enqueue a rerender of a component
+ * @param {import('./internal').Component} c The component to rerender
+ */
+export function enqueueRender(c) {
+ if (
+ (!c._dirty &&
+ (c._dirty = true) &&
+ rerenderQueue.push(c) &&
+ !process._rerenderCount++) ||
+ prevDebounce !== options.debounceRendering
+ ) {
+ prevDebounce = options.debounceRendering;
+ (prevDebounce || defer)(process);
+ }
+}
+
+/** Flush the render queue by rerendering all queued components */
+function process() {
+ let queue;
+ while ((process._rerenderCount = rerenderQueue.length)) {
+ queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
+ rerenderQueue = [];
+ // Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
+ // process() calls from getting scheduled while `queue` is still being consumed.
+ queue.some(c => {
+ if (c._dirty) renderComponent(c);
+ });
+ }
+}
+process._rerenderCount = 0;
diff --git a/preact/src/constants.js b/preact/src/constants.js
new file mode 100644
index 0000000..dddc9a3
--- /dev/null
+++ b/preact/src/constants.js
@@ -0,0 +1,3 @@
+export const EMPTY_OBJ = {};
+export const EMPTY_ARR = [];
+export const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
diff --git a/preact/src/create-context.js b/preact/src/create-context.js
new file mode 100644
index 0000000..750517d
--- /dev/null
+++ b/preact/src/create-context.js
@@ -0,0 +1,68 @@
+import { enqueueRender } from './component';
+
+export let i = 0;
+
+export function createContext(defaultValue, contextId) {
+ contextId = '__cC' + i++;
+
+ const context = {
+ _id: contextId,
+ _defaultValue: defaultValue,
+ /** @type {import('./internal').FunctionComponent} */
+ Consumer(props, contextValue) {
+ // return props.children(
+ // context[contextId] ? context[contextId].props.value : defaultValue
+ // );
+ return props.children(contextValue);
+ },
+ /** @type {import('./internal').FunctionComponent} */
+ Provider(props) {
+ if (!this.getChildContext) {
+ let subs = [];
+ let ctx = {};
+ ctx[contextId] = this;
+
+ this.getChildContext = () => ctx;
+
+ this.shouldComponentUpdate = function(_props) {
+ if (this.props.value !== _props.value) {
+ // I think the forced value propagation here was only needed when `options.debounceRendering` was being bypassed:
+ // https://github.com/preactjs/preact/commit/4d339fb803bea09e9f198abf38ca1bf8ea4b7771#diff-54682ce380935a717e41b8bfc54737f6R358
+ // In those cases though, even with the value corrected, we're double-rendering all nodes.
+ // It might be better to just tell folks not to use force-sync mode.
+ // Currently, using `useContext()` in a class component will overwrite its `this.context` value.
+ // subs.some(c => {
+ // c.context = _props.value;
+ // enqueueRender(c);
+ // });
+
+ // subs.some(c => {
+ // c.context[contextId] = _props.value;
+ // enqueueRender(c);
+ // });
+ subs.some(enqueueRender);
+ }
+ };
+
+ this.sub = c => {
+ subs.push(c);
+ let old = c.componentWillUnmount;
+ c.componentWillUnmount = () => {
+ subs.splice(subs.indexOf(c), 1);
+ if (old) old.call(c);
+ };
+ };
+ }
+
+ return props.children;
+ }
+ };
+
+ // Devtools needs access to the context object when it
+ // encounters a Provider. This is necessary to support
+ // setting `displayName` on the context object instead
+ // of on the component itself. See:
+ // https://reactjs.org/docs/context.html#contextdisplayname
+
+ return (context.Provider._contextRef = context.Consumer.contextType = context);
+}
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;
diff --git a/preact/src/diff/catch-error.js b/preact/src/diff/catch-error.js
new file mode 100644
index 0000000..893a076
--- /dev/null
+++ b/preact/src/diff/catch-error.js
@@ -0,0 +1,38 @@
+/**
+ * Find the closest error boundary to a thrown error and call it
+ * @param {object} error The thrown value
+ * @param {import('../internal').VNode} vnode The vnode that threw
+ * the error that was caught (except for unmounting when this parameter
+ * is the highest parent that was being unmounted)
+ */
+export function _catchError(error, vnode) {
+ /** @type {import('../internal').Component} */
+ let component, ctor, handled;
+
+ for (; (vnode = vnode._parent); ) {
+ if ((component = vnode._component) && !component._processingException) {
+ try {
+ ctor = component.constructor;
+
+ if (ctor && ctor.getDerivedStateFromError != null) {
+ component.setState(ctor.getDerivedStateFromError(error));
+ handled = component._dirty;
+ }
+
+ if (component.componentDidCatch != null) {
+ component.componentDidCatch(error);
+ handled = component._dirty;
+ }
+
+ // This is an error boundary. Mark it as having bailed out, and whether it was mid-hydration.
+ if (handled) {
+ return (component._pendingError = component);
+ }
+ } catch (e) {
+ error = e;
+ }
+ }
+ }
+
+ throw error;
+}
diff --git a/preact/src/diff/children.js b/preact/src/diff/children.js
new file mode 100644
index 0000000..204e3e4
--- /dev/null
+++ b/preact/src/diff/children.js
@@ -0,0 +1,347 @@
+import { diff, unmount, applyRef } from './index';
+import { createVNode, Fragment } from '../create-element';
+import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
+import { getDomSibling } from '../component';
+
+/**
+ * Diff the children of a virtual node
+ * @param {import('../internal').PreactElement} parentDom The DOM element whose
+ * children are being diffed
+ * @param {import('../internal').ComponentChildren[]} renderResult
+ * @param {import('../internal').VNode} newParentVNode The new virtual
+ * node whose children should be diff'ed against oldParentVNode
+ * @param {import('../internal').VNode} oldParentVNode The old virtual
+ * node whose children should be diff'ed against newParentVNode
+ * @param {object} globalContext The current context object - modified by getChildContext
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node
+ * @param {Array<import('../internal').PreactElement>} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').PreactElement} oldDom The current attached DOM
+ * element any new dom elements should be placed around. Likely `null` on first
+ * render (except when hydrating). Can be a sibling DOM element when diffing
+ * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
+ * @param {boolean} isHydrating Whether or not we are in hydration
+ */
+export function diffChildren(
+ parentDom,
+ renderResult,
+ newParentVNode,
+ oldParentVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+) {
+ let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
+
+ // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
+ // as EMPTY_OBJ._children should be `undefined`.
+ let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
+
+ let oldChildrenLength = oldChildren.length;
+
+ newParentVNode._children = [];
+ for (i = 0; i < renderResult.length; i++) {
+ childVNode = renderResult[i];
+
+ if (childVNode == null || typeof childVNode == 'boolean') {
+ childVNode = newParentVNode._children[i] = null;
+ }
+ // If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
+ // or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
+ // it's own DOM & etc. pointers
+ else if (
+ typeof childVNode == 'string' ||
+ typeof childVNode == 'number' ||
+ // eslint-disable-next-line valid-typeof
+ typeof childVNode == 'bigint'
+ ) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ null,
+ childVNode,
+ null,
+ null,
+ childVNode
+ );
+ } else if (Array.isArray(childVNode)) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ Fragment,
+ { children: childVNode },
+ null,
+ null,
+ null
+ );
+ } else if (childVNode._depth > 0) {
+ // VNode is already in use, clone it. This can happen in the following
+ // scenario:
+ // const reuse = <div />
+ // <div>{reuse}<span />{reuse}</div>
+ childVNode = newParentVNode._children[i] = createVNode(
+ childVNode.type,
+ childVNode.props,
+ childVNode.key,
+ null,
+ childVNode._original
+ );
+ } else {
+ childVNode = newParentVNode._children[i] = childVNode;
+ }
+
+ // Terser removes the `continue` here and wraps the loop body
+ // in a `if (childVNode) { ... } condition
+ if (childVNode == null) {
+ continue;
+ }
+
+ childVNode._parent = newParentVNode;
+ childVNode._depth = newParentVNode._depth + 1;
+
+ // Check if we find a corresponding element in oldChildren.
+ // If found, delete the array item by setting to `undefined`.
+ // We use `undefined`, as `null` is reserved for empty placeholders
+ // (holes).
+ oldVNode = oldChildren[i];
+
+ if (
+ oldVNode === null ||
+ (oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type)
+ ) {
+ oldChildren[i] = undefined;
+ } else {
+ // Either oldVNode === undefined or oldChildrenLength > 0,
+ // so after this loop oldVNode == null or oldVNode is a valid value.
+ for (j = 0; j < oldChildrenLength; j++) {
+ oldVNode = oldChildren[j];
+ // If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
+ // We always match by type (in either case).
+ if (
+ oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type
+ ) {
+ oldChildren[j] = undefined;
+ break;
+ }
+ oldVNode = null;
+ }
+ }
+
+ oldVNode = oldVNode || EMPTY_OBJ;
+
+ // Morph the old element into the new one, but don't append it to the dom yet
+ diff(
+ parentDom,
+ childVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+ );
+
+ newDom = childVNode._dom;
+
+ if ((j = childVNode.ref) && oldVNode.ref != j) {
+ if (!refs) refs = [];
+ if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
+ refs.push(j, childVNode._component || newDom, childVNode);
+ }
+
+ if (newDom != null) {
+ if (firstChildDom == null) {
+ firstChildDom = newDom;
+ }
+
+ if (
+ typeof childVNode.type == 'function' &&
+ childVNode._children != null && // Can be null if childVNode suspended
+ childVNode._children === oldVNode._children
+ ) {
+ childVNode._nextDom = oldDom = reorderChildren(
+ childVNode,
+ oldDom,
+ parentDom
+ );
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+ );
+ }
+
+ // Browsers will infer an option's `value` from `textContent` when
+ // no value is present. This essentially bypasses our code to set it
+ // later in `diff()`. It works fine in all browsers except for IE11
+ // where it breaks setting `select.value`. There it will be always set
+ // to an empty string. Re-applying an options value will fix that, so
+ // there are probably some internal data structures that aren't
+ // updated properly.
+ //
+ // To fix it we make sure to reset the inferred value, so that our own
+ // value check in `diff()` won't be skipped.
+ if (!isHydrating && newParentVNode.type === 'option') {
+ // @ts-ignore We have validated that the type of parentDOM is 'option'
+ // in the above check
+ parentDom.value = '';
+ } else if (typeof newParentVNode.type == 'function') {
+ // Because the newParentVNode is Fragment-like, we need to set it's
+ // _nextDom property to the nextSibling of its last child DOM node.
+ //
+ // `oldDom` contains the correct value here because if the last child
+ // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
+ // If the last child is a DOM VNode, then oldDom will be set to that DOM
+ // node's nextSibling.
+ newParentVNode._nextDom = oldDom;
+ }
+ } else if (
+ oldDom &&
+ oldVNode._dom == oldDom &&
+ oldDom.parentNode != parentDom
+ ) {
+ // The above condition is to handle null placeholders. See test in placeholder.test.js:
+ // `efficiently replace null placeholders in parent rerenders`
+ oldDom = getDomSibling(oldVNode);
+ }
+ }
+
+ newParentVNode._dom = firstChildDom;
+
+ // Remove remaining oldChildren if there are any.
+ for (i = oldChildrenLength; i--; ) {
+ if (oldChildren[i] != null) {
+ if (
+ typeof newParentVNode.type == 'function' &&
+ oldChildren[i]._dom != null &&
+ oldChildren[i]._dom == newParentVNode._nextDom
+ ) {
+ // If the newParentVNode.__nextDom points to a dom node that is about to
+ // be unmounted, then get the next sibling of that vnode and set
+ // _nextDom to it
+ newParentVNode._nextDom = getDomSibling(oldParentVNode, i + 1);
+ }
+
+ unmount(oldChildren[i], oldChildren[i]);
+ }
+ }
+
+ // Set refs only after unmount
+ if (refs) {
+ for (i = 0; i < refs.length; i++) {
+ applyRef(refs[i], refs[++i], refs[++i]);
+ }
+ }
+}
+
+function reorderChildren(childVNode, oldDom, parentDom) {
+ for (let tmp = 0; tmp < childVNode._children.length; tmp++) {
+ let vnode = childVNode._children[tmp];
+ if (vnode) {
+ // We typically enter this code path on sCU bailout, where we copy
+ // oldVNode._children to newVNode._children. If that is the case, we need
+ // to update the old children's _parent pointer to point to the newVNode
+ // (childVNode here).
+ vnode._parent = childVNode;
+
+ if (typeof vnode.type == 'function') {
+ oldDom = reorderChildren(vnode, oldDom, parentDom);
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ vnode,
+ vnode,
+ childVNode._children,
+ vnode._dom,
+ oldDom
+ );
+ }
+ }
+ }
+
+ return oldDom;
+}
+
+/**
+ * Flatten and loop through the children of a virtual node
+ * @param {import('../index').ComponentChildren} children The unflattened
+ * children of a virtual node
+ * @returns {import('../internal').VNode[]}
+ */
+export function toChildArray(children, out) {
+ out = out || [];
+ if (children == null || typeof children == 'boolean') {
+ } else if (Array.isArray(children)) {
+ children.some(child => {
+ toChildArray(child, out);
+ });
+ } else {
+ out.push(children);
+ }
+ return out;
+}
+
+function placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+) {
+ let nextDom;
+ if (childVNode._nextDom !== undefined) {
+ // Only Fragments or components that return Fragment like VNodes will
+ // have a non-undefined _nextDom. Continue the diff from the sibling
+ // of last DOM child of this child VNode
+ nextDom = childVNode._nextDom;
+
+ // Eagerly cleanup _nextDom. We don't need to persist the value because
+ // it is only used by `diffChildren` to determine where to resume the diff after
+ // diffing Components and Fragments. Once we store it the nextDOM local var, we
+ // can clean up the property
+ childVNode._nextDom = undefined;
+ } else if (
+ oldVNode == null ||
+ newDom != oldDom ||
+ newDom.parentNode == null
+ ) {
+ outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
+ parentDom.appendChild(newDom);
+ nextDom = null;
+ } else {
+ // `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
+ for (
+ let sibDom = oldDom, j = 0;
+ (sibDom = sibDom.nextSibling) && j < oldChildren.length;
+ j += 2
+ ) {
+ if (sibDom == newDom) {
+ break outer;
+ }
+ }
+ parentDom.insertBefore(newDom, oldDom);
+ nextDom = oldDom;
+ }
+ }
+
+ // If we have pre-calculated the nextDOM node, use it. Else calculate it now
+ // Strictly check for `undefined` here cuz `null` is a valid value of `nextDom`.
+ // See more detail in create-element.js:createVNode
+ if (nextDom !== undefined) {
+ oldDom = nextDom;
+ } else {
+ oldDom = newDom.nextSibling;
+ }
+
+ return oldDom;
+}
diff --git a/preact/src/diff/index.js b/preact/src/diff/index.js
new file mode 100644
index 0000000..de63843
--- /dev/null
+++ b/preact/src/diff/index.js
@@ -0,0 +1,514 @@
+import { EMPTY_OBJ } from '../constants';
+import { Component, getDomSibling } from '../component';
+import { Fragment } from '../create-element';
+import { diffChildren } from './children';
+import { diffProps, setProperty } from './props';
+import { assign, removeNode, slice } from '../util';
+import options from '../options';
+
+/**
+ * Diff two virtual nodes and apply proper changes to the DOM
+ * @param {import('../internal').PreactElement} parentDom The parent of the DOM element
+ * @param {import('../internal').VNode} newVNode The new virtual node
+ * @param {import('../internal').VNode} oldVNode The old virtual node
+ * @param {object} globalContext The current context object. Modified by getChildContext
+ * @param {boolean} isSvg Whether or not this element is an SVG node
+ * @param {Array<import('../internal').PreactElement>} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').PreactElement} oldDom The current attached DOM
+ * element any new dom elements should be placed around. Likely `null` on first
+ * render (except when hydrating). Can be a sibling DOM element when diffing
+ * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
+ * @param {boolean} [isHydrating] Whether or not we are in hydration
+ */
+export function diff(
+ parentDom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+) {
+ let tmp,
+ newType = newVNode.type;
+
+ // When passing through createElement it assigns the object
+ // constructor as undefined. This to prevent JSON-injection.
+ if (newVNode.constructor !== undefined) return null;
+
+ // If the previous diff bailed out, resume creating/hydrating.
+ if (oldVNode._hydrating != null) {
+ isHydrating = oldVNode._hydrating;
+ oldDom = newVNode._dom = oldVNode._dom;
+ // if we resume, we want the tree to be "unlocked"
+ newVNode._hydrating = null;
+ excessDomChildren = [oldDom];
+ }
+
+ if ((tmp = options._diff)) tmp(newVNode);
+
+ try {
+ outer: if (typeof newType == 'function') {
+ let c, isNew, oldProps, oldState, snapshot, clearProcessingException;
+ let newProps = newVNode.props;
+
+ // Necessary for createContext api. Setting this property will pass
+ // the context value as `this.context` just for this component.
+ tmp = newType.contextType;
+ let provider = tmp && globalContext[tmp._id];
+ let componentContext = tmp
+ ? provider
+ ? provider.props.value
+ : tmp._defaultValue
+ : globalContext;
+
+ // Get component and set it to `c`
+ if (oldVNode._component) {
+ c = newVNode._component = oldVNode._component;
+ clearProcessingException = c._processingException = c._pendingError;
+ } else {
+ // Instantiate the new component
+ if ('prototype' in newType && newType.prototype.render) {
+ // @ts-ignore The check above verifies that newType is suppose to be constructed
+ newVNode._component = c = new newType(newProps, componentContext); // eslint-disable-line new-cap
+ } else {
+ // @ts-ignore Trust me, Component implements the interface we want
+ newVNode._component = c = new Component(newProps, componentContext);
+ c.constructor = newType;
+ c.render = doRender;
+ }
+ if (provider) provider.sub(c);
+
+ c.props = newProps;
+ if (!c.state) c.state = {};
+ c.context = componentContext;
+ c._globalContext = globalContext;
+ isNew = c._dirty = true;
+ c._renderCallbacks = [];
+ }
+
+ // Invoke getDerivedStateFromProps
+ if (c._nextState == null) {
+ c._nextState = c.state;
+ }
+ if (newType.getDerivedStateFromProps != null) {
+ if (c._nextState == c.state) {
+ c._nextState = assign({}, c._nextState);
+ }
+
+ assign(
+ c._nextState,
+ newType.getDerivedStateFromProps(newProps, c._nextState)
+ );
+ }
+
+ oldProps = c.props;
+ oldState = c.state;
+
+ // Invoke pre-render lifecycle methods
+ if (isNew) {
+ if (
+ newType.getDerivedStateFromProps == null &&
+ c.componentWillMount != null
+ ) {
+ c.componentWillMount();
+ }
+
+ if (c.componentDidMount != null) {
+ c._renderCallbacks.push(c.componentDidMount);
+ }
+ } else {
+ if (
+ newType.getDerivedStateFromProps == null &&
+ newProps !== oldProps &&
+ c.componentWillReceiveProps != null
+ ) {
+ c.componentWillReceiveProps(newProps, componentContext);
+ }
+
+ if (
+ (!c._force &&
+ c.shouldComponentUpdate != null &&
+ c.shouldComponentUpdate(
+ newProps,
+ c._nextState,
+ componentContext
+ ) === false) ||
+ newVNode._original === oldVNode._original
+ ) {
+ c.props = newProps;
+ c.state = c._nextState;
+ // More info about this here: https://gist.github.com/JoviDeCroock/bec5f2ce93544d2e6070ef8e0036e4e8
+ if (newVNode._original !== oldVNode._original) c._dirty = false;
+ c._vnode = newVNode;
+ newVNode._dom = oldVNode._dom;
+ newVNode._children = oldVNode._children;
+ newVNode._children.forEach(vnode => {
+ if (vnode) vnode._parent = newVNode;
+ });
+ if (c._renderCallbacks.length) {
+ commitQueue.push(c);
+ }
+
+ break outer;
+ }
+
+ if (c.componentWillUpdate != null) {
+ c.componentWillUpdate(newProps, c._nextState, componentContext);
+ }
+
+ if (c.componentDidUpdate != null) {
+ c._renderCallbacks.push(() => {
+ c.componentDidUpdate(oldProps, oldState, snapshot);
+ });
+ }
+ }
+
+ c.context = componentContext;
+ c.props = newProps;
+ c.state = c._nextState;
+
+ if ((tmp = options._render)) tmp(newVNode);
+
+ c._dirty = false;
+ c._vnode = newVNode;
+ c._parentDom = parentDom;
+
+ tmp = c.render(c.props, c.state, c.context);
+
+ // Handle setState called in render, see #2553
+ c.state = c._nextState;
+
+ if (c.getChildContext != null) {
+ globalContext = assign(assign({}, globalContext), c.getChildContext());
+ }
+
+ if (!isNew && c.getSnapshotBeforeUpdate != null) {
+ snapshot = c.getSnapshotBeforeUpdate(oldProps, oldState);
+ }
+
+ let isTopLevelFragment =
+ tmp != null && tmp.type === Fragment && tmp.key == null;
+ let renderResult = isTopLevelFragment ? tmp.props.children : tmp;
+
+ diffChildren(
+ parentDom,
+ Array.isArray(renderResult) ? renderResult : [renderResult],
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+ );
+
+ c.base = newVNode._dom;
+
+ // We successfully rendered this VNode, unset any stored hydration/bailout state:
+ newVNode._hydrating = null;
+
+ if (c._renderCallbacks.length) {
+ commitQueue.push(c);
+ }
+
+ if (clearProcessingException) {
+ c._pendingError = c._processingException = null;
+ }
+
+ c._force = false;
+ } else if (
+ excessDomChildren == null &&
+ newVNode._original === oldVNode._original
+ ) {
+ newVNode._children = oldVNode._children;
+ newVNode._dom = oldVNode._dom;
+ } else {
+ newVNode._dom = diffElementNodes(
+ oldVNode._dom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ isHydrating
+ );
+ }
+
+ if ((tmp = options.diffed)) tmp(newVNode);
+ } catch (e) {
+ newVNode._original = null;
+ // if hydrating or creating initial tree, bailout preserves DOM:
+ if (isHydrating || excessDomChildren != null) {
+ newVNode._dom = oldDom;
+ newVNode._hydrating = !!isHydrating;
+ excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
+ // ^ could possibly be simplified to:
+ // excessDomChildren.length = 0;
+ }
+ options._catchError(e, newVNode, oldVNode);
+ }
+}
+
+/**
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').VNode} root
+ */
+export function commitRoot(commitQueue, root) {
+ if (options._commit) options._commit(root, commitQueue);
+
+ commitQueue.some(c => {
+ try {
+ // @ts-ignore Reuse the commitQueue variable here so the type changes
+ commitQueue = c._renderCallbacks;
+ c._renderCallbacks = [];
+ commitQueue.some(cb => {
+ // @ts-ignore See above ts-ignore on commitQueue
+ cb.call(c);
+ });
+ } catch (e) {
+ options._catchError(e, c._vnode);
+ }
+ });
+}
+
+/**
+ * Diff two virtual nodes representing DOM element
+ * @param {import('../internal').PreactElement} dom The DOM element representing
+ * the virtual nodes being diffed
+ * @param {import('../internal').VNode} newVNode The new virtual node
+ * @param {import('../internal').VNode} oldVNode The old virtual node
+ * @param {object} globalContext The current context object
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node
+ * @param {*} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {boolean} isHydrating Whether or not we are in hydration
+ * @returns {import('../internal').PreactElement}
+ */
+function diffElementNodes(
+ dom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ isHydrating
+) {
+ let oldProps = oldVNode.props;
+ let newProps = newVNode.props;
+ let nodeType = newVNode.type;
+ let i = 0;
+
+ // Tracks entering and exiting SVG namespace when descending through the tree.
+ if (nodeType === 'svg') isSvg = true;
+
+ if (excessDomChildren != null) {
+ for (; i < excessDomChildren.length; i++) {
+ const child = excessDomChildren[i];
+
+ // if newVNode matches an element in excessDomChildren or the `dom`
+ // argument matches an element in excessDomChildren, remove it from
+ // excessDomChildren so it isn't later removed in diffChildren
+ if (
+ child &&
+ (child === dom ||
+ (nodeType ? child.localName == nodeType : child.nodeType == 3))
+ ) {
+ dom = child;
+ excessDomChildren[i] = null;
+ break;
+ }
+ }
+ }
+
+ if (dom == null) {
+ if (nodeType === null) {
+ // @ts-ignore createTextNode returns Text, we expect PreactElement
+ return document.createTextNode(newProps);
+ }
+
+ if (isSvg) {
+ dom = document.createElementNS(
+ 'http://www.w3.org/2000/svg',
+ // @ts-ignore We know `newVNode.type` is a string
+ nodeType
+ );
+ } else {
+ dom = document.createElement(
+ // @ts-ignore We know `newVNode.type` is a string
+ nodeType,
+ newProps.is && newProps
+ );
+ }
+
+ // we created a new parent, so none of the previously attached children can be reused:
+ excessDomChildren = null;
+ // we are creating a new node, so we can assume this is a new subtree (in case we are hydrating), this deopts the hydrate
+ isHydrating = false;
+ }
+
+ if (nodeType === null) {
+ // During hydration, we still have to split merged text from SSR'd HTML.
+ if (oldProps !== newProps && (!isHydrating || dom.data !== newProps)) {
+ dom.data = newProps;
+ }
+ } else {
+ // If excessDomChildren was not null, repopulate it with the current element's children:
+ excessDomChildren = excessDomChildren && slice.call(dom.childNodes);
+
+ oldProps = oldVNode.props || EMPTY_OBJ;
+
+ let oldHtml = oldProps.dangerouslySetInnerHTML;
+ let newHtml = newProps.dangerouslySetInnerHTML;
+
+ // During hydration, props are not diffed at all (including dangerouslySetInnerHTML)
+ // @TODO we should warn in debug mode when props don't match here.
+ if (!isHydrating) {
+ // But, if we are in a situation where we are using existing DOM (e.g. replaceNode)
+ // we should read the existing DOM attributes to diff them
+ if (excessDomChildren != null) {
+ oldProps = {};
+ for (i = 0; i < dom.attributes.length; i++) {
+ oldProps[dom.attributes[i].name] = dom.attributes[i].value;
+ }
+ }
+
+ if (newHtml || oldHtml) {
+ // Avoid re-applying the same '__html' if it did not changed between re-render
+ if (
+ !newHtml ||
+ ((!oldHtml || newHtml.__html != oldHtml.__html) &&
+ newHtml.__html !== dom.innerHTML)
+ ) {
+ dom.innerHTML = (newHtml && newHtml.__html) || '';
+ }
+ }
+ }
+
+ diffProps(dom, newProps, oldProps, isSvg, isHydrating);
+
+ // If the new vnode didn't have dangerouslySetInnerHTML, diff its children
+ if (newHtml) {
+ newVNode._children = [];
+ } else {
+ i = newVNode.props.children;
+ diffChildren(
+ dom,
+ Array.isArray(i) ? i : [i],
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg && nodeType !== 'foreignObject',
+ excessDomChildren,
+ commitQueue,
+ excessDomChildren
+ ? excessDomChildren[0]
+ : oldVNode._children && getDomSibling(oldVNode, 0),
+ isHydrating
+ );
+
+ // Remove children that are not part of any vnode.
+ if (excessDomChildren != null) {
+ for (i = excessDomChildren.length; i--; ) {
+ if (excessDomChildren[i] != null) removeNode(excessDomChildren[i]);
+ }
+ }
+ }
+
+ // (as above, don't diff props during hydration)
+ if (!isHydrating) {
+ if (
+ 'value' in newProps &&
+ (i = newProps.value) !== undefined &&
+ // #2756 For the <progress>-element the initial value is 0,
+ // despite the attribute not being present. When the attribute
+ // is missing the progress bar is treated as indeterminate.
+ // To fix that we'll always update it when it is 0 for progress elements
+ (i !== dom.value || (nodeType === 'progress' && !i))
+ ) {
+ setProperty(dom, 'value', i, oldProps.value, false);
+ }
+ if (
+ 'checked' in newProps &&
+ (i = newProps.checked) !== undefined &&
+ i !== dom.checked
+ ) {
+ setProperty(dom, 'checked', i, oldProps.checked, false);
+ }
+ }
+ }
+
+ return dom;
+}
+
+/**
+ * Invoke or update a ref, depending on whether it is a function or object ref.
+ * @param {object|function} ref
+ * @param {any} value
+ * @param {import('../internal').VNode} vnode
+ */
+export function applyRef(ref, value, vnode) {
+ try {
+ if (typeof ref == 'function') ref(value);
+ else ref.current = value;
+ } catch (e) {
+ options._catchError(e, vnode);
+ }
+}
+
+/**
+ * Unmount a virtual node from the tree and apply DOM changes
+ * @param {import('../internal').VNode} vnode The virtual node to unmount
+ * @param {import('../internal').VNode} parentVNode The parent of the VNode that
+ * initiated the unmount
+ * @param {boolean} [skipRemove] Flag that indicates that a parent node of the
+ * current element is already detached from the DOM.
+ */
+export function unmount(vnode, parentVNode, skipRemove) {
+ let r;
+ if (options.unmount) options.unmount(vnode);
+
+ if ((r = vnode.ref)) {
+ if (!r.current || r.current === vnode._dom) applyRef(r, null, parentVNode);
+ }
+
+ if ((r = vnode._component) != null) {
+ if (r.componentWillUnmount) {
+ try {
+ r.componentWillUnmount();
+ } catch (e) {
+ options._catchError(e, parentVNode);
+ }
+ }
+
+ r.base = r._parentDom = null;
+ }
+
+ if ((r = vnode._children)) {
+ for (let i = 0; i < r.length; i++) {
+ if (r[i]) {
+ unmount(r[i], parentVNode, typeof vnode.type != 'function');
+ }
+ }
+ }
+
+ if (!skipRemove && vnode._dom != null) removeNode(vnode._dom);
+
+ // Must be set to `undefined` to properly clean up `_nextDom`
+ // for which `null` is a valid value. See comment in `create-element.js`
+ vnode._dom = vnode._nextDom = undefined;
+}
+
+/** The `.render()` method for a PFC backing instance. */
+function doRender(props, state, context) {
+ return this.constructor(props, context);
+}
diff --git a/preact/src/diff/props.js b/preact/src/diff/props.js
new file mode 100644
index 0000000..472d997
--- /dev/null
+++ b/preact/src/diff/props.js
@@ -0,0 +1,158 @@
+import { IS_NON_DIMENSIONAL } from '../constants';
+import options from '../options';
+
+/**
+ * Diff the old and new properties of a VNode and apply changes to the DOM node
+ * @param {import('../internal').PreactElement} dom The DOM node to apply
+ * changes to
+ * @param {object} newProps The new props
+ * @param {object} oldProps The old props
+ * @param {boolean} isSvg Whether or not this node is an SVG node
+ * @param {boolean} hydrate Whether or not we are in hydration mode
+ */
+export function diffProps(dom, newProps, oldProps, isSvg, hydrate) {
+ let i;
+
+ for (i in oldProps) {
+ if (i !== 'children' && i !== 'key' && !(i in newProps)) {
+ setProperty(dom, i, null, oldProps[i], isSvg);
+ }
+ }
+
+ for (i in newProps) {
+ if (
+ (!hydrate || typeof newProps[i] == 'function') &&
+ i !== 'children' &&
+ i !== 'key' &&
+ i !== 'value' &&
+ i !== 'checked' &&
+ oldProps[i] !== newProps[i]
+ ) {
+ setProperty(dom, i, newProps[i], oldProps[i], isSvg);
+ }
+ }
+}
+
+function setStyle(style, key, value) {
+ if (key[0] === '-') {
+ style.setProperty(key, value);
+ } else if (value == null) {
+ style[key] = '';
+ } else if (typeof value != 'number' || IS_NON_DIMENSIONAL.test(key)) {
+ style[key] = value;
+ } else {
+ style[key] = value + 'px';
+ }
+}
+
+/**
+ * Set a property value on a DOM node
+ * @param {import('../internal').PreactElement} dom The DOM node to modify
+ * @param {string} name The name of the property to set
+ * @param {*} value The value to set the property to
+ * @param {*} oldValue The old value the property had
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node or not
+ */
+export function setProperty(dom, name, value, oldValue, isSvg) {
+ let useCapture;
+
+ o: if (name === 'style') {
+ if (typeof value == 'string') {
+ dom.style.cssText = value;
+ } else {
+ if (typeof oldValue == 'string') {
+ dom.style.cssText = oldValue = '';
+ }
+
+ if (oldValue) {
+ for (name in oldValue) {
+ if (!(value && name in value)) {
+ setStyle(dom.style, name, '');
+ }
+ }
+ }
+
+ if (value) {
+ for (name in value) {
+ if (!oldValue || value[name] !== oldValue[name]) {
+ setStyle(dom.style, name, value[name]);
+ }
+ }
+ }
+ }
+ }
+ // Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6
+ else if (name[0] === 'o' && name[1] === 'n') {
+ useCapture = name !== (name = name.replace(/Capture$/, ''));
+
+ // Infer correct casing for DOM built-in events:
+ if (name.toLowerCase() in dom) name = name.toLowerCase().slice(2);
+ else name = name.slice(2);
+
+ if (!dom._listeners) dom._listeners = {};
+ dom._listeners[name + useCapture] = value;
+
+ if (value) {
+ if (!oldValue) {
+ const handler = useCapture ? eventProxyCapture : eventProxy;
+ dom.addEventListener(name, handler, useCapture);
+ }
+ } else {
+ const handler = useCapture ? eventProxyCapture : eventProxy;
+ dom.removeEventListener(name, handler, useCapture);
+ }
+ } else if (name !== 'dangerouslySetInnerHTML') {
+ if (isSvg) {
+ // Normalize incorrect prop usage for SVG:
+ // - xlink:href / xlinkHref --> href (xlink:href was removed from SVG and isn't needed)
+ // - className --> class
+ name = name.replace(/xlink[H:h]/, 'h').replace(/sName$/, 's');
+ } else if (
+ name !== 'href' &&
+ name !== 'list' &&
+ name !== 'form' &&
+ // Default value in browsers is `-1` and an empty string is
+ // cast to `0` instead
+ name !== 'tabIndex' &&
+ name !== 'download' &&
+ name in dom
+ ) {
+ try {
+ dom[name] = value == null ? '' : value;
+ // labelled break is 1b smaller here than a return statement (sorry)
+ break o;
+ } catch (e) {}
+ }
+
+ // ARIA-attributes have a different notion of boolean values.
+ // The value `false` is different from the attribute not
+ // existing on the DOM, so we can't remove it. For non-boolean
+ // ARIA-attributes we could treat false as a removal, but the
+ // amount of exceptions would cost us too many bytes. On top of
+ // that other VDOM frameworks also always stringify `false`.
+
+ if (typeof value === 'function') {
+ // never serialize functions as attribute values
+ } else if (
+ value != null &&
+ (value !== false || (name[0] === 'a' && name[1] === 'r'))
+ ) {
+ dom.setAttribute(name, value);
+ } else {
+ dom.removeAttribute(name);
+ }
+ }
+}
+
+/**
+ * Proxy an event to hooked event handlers
+ * @param {Event} e The event object from the browser
+ * @private
+ */
+function eventProxy(e) {
+ this._listeners[e.type + false](options.event ? options.event(e) : e);
+}
+
+function eventProxyCapture(e) {
+ this._listeners[e.type + true](options.event ? options.event(e) : e);
+}
diff --git a/preact/src/index.d.ts b/preact/src/index.d.ts
new file mode 100644
index 0000000..e55f978
--- /dev/null
+++ b/preact/src/index.d.ts
@@ -0,0 +1,310 @@
+export as namespace preact;
+
+import { JSXInternal } from './jsx';
+
+export import JSX = JSXInternal;
+
+//
+// Preact Virtual DOM
+// -----------------------------------
+
+export interface VNode<P = {}> {
+ type: ComponentType<P> | string;
+ props: P & { children: ComponentChildren };
+ key: Key;
+ /**
+ * ref is not guaranteed by React.ReactElement, for compatibility reasons
+ * with popular react libs we define it as optional too
+ */
+ ref?: Ref<any> | null;
+ /**
+ * The time this `vnode` started rendering. Will only be set when
+ * the devtools are attached.
+ * Default value: `0`
+ */
+ startTime?: number;
+ /**
+ * The time that the rendering of this `vnode` was completed. Will only be
+ * set when the devtools are attached.
+ * Default value: `-1`
+ */
+ endTime?: number;
+}
+
+//
+// Preact Component interface
+// -----------------------------------
+
+export type Key = string | number | any;
+
+export type RefObject<T> = { current: T | null };
+export type RefCallback<T> = (instance: T | null) => void;
+export type Ref<T> = RefObject<T> | RefCallback<T>;
+
+export type ComponentChild =
+ | VNode<any>
+ | object
+ | string
+ | number
+ | bigint
+ | boolean
+ | null
+ | undefined;
+export type ComponentChildren = ComponentChild[] | ComponentChild;
+
+export interface Attributes {
+ key?: Key;
+ jsx?: boolean;
+}
+
+export interface ClassAttributes<T> extends Attributes {
+ ref?: Ref<T>;
+}
+
+export interface PreactDOMAttributes {
+ children?: ComponentChildren;
+ dangerouslySetInnerHTML?: {
+ __html: string;
+ };
+}
+
+export type RenderableProps<P, RefType = any> = P &
+ Readonly<Attributes & { children?: ComponentChildren; ref?: Ref<RefType> }>;
+
+export type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
+export type ComponentFactory<P = {}> = ComponentType<P>;
+
+export type ComponentProps<
+ C extends ComponentType<any> | keyof JSXInternal.IntrinsicElements
+> = C extends ComponentType<infer P>
+ ? P
+ : C extends keyof JSXInternal.IntrinsicElements
+ ? JSXInternal.IntrinsicElements[C]
+ : never;
+
+export interface FunctionComponent<P = {}> {
+ (props: RenderableProps<P>, context?: any): VNode<any> | null;
+ displayName?: string;
+ defaultProps?: Partial<P>;
+}
+export interface FunctionalComponent<P = {}> extends FunctionComponent<P> {}
+
+export interface ComponentClass<P = {}, S = {}> {
+ new (props: P, context?: any): Component<P, S>;
+ displayName?: string;
+ defaultProps?: Partial<P>;
+ contextType?: Context<any>;
+ getDerivedStateFromProps?(
+ props: Readonly<P>,
+ state: Readonly<S>
+ ): Partial<S> | null;
+ getDerivedStateFromError?(error: any): Partial<S> | null;
+}
+export interface ComponentConstructor<P = {}, S = {}>
+ extends ComponentClass<P, S> {}
+
+// Type alias for a component instance considered generally, whether stateless or stateful.
+export type AnyComponent<P = {}, S = {}> =
+ | FunctionComponent<P>
+ | Component<P, S>;
+
+export interface Component<P = {}, S = {}> {
+ componentWillMount?(): void;
+ componentDidMount?(): void;
+ componentWillUnmount?(): void;
+ getChildContext?(): object;
+ componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
+ shouldComponentUpdate?(
+ nextProps: Readonly<P>,
+ nextState: Readonly<S>,
+ nextContext: any
+ ): boolean;
+ componentWillUpdate?(
+ nextProps: Readonly<P>,
+ nextState: Readonly<S>,
+ nextContext: any
+ ): void;
+ getSnapshotBeforeUpdate?(oldProps: Readonly<P>, oldState: Readonly<S>): any;
+ componentDidUpdate?(
+ previousProps: Readonly<P>,
+ previousState: Readonly<S>,
+ snapshot: any
+ ): void;
+ componentDidCatch?(error: any, errorInfo: any): void;
+}
+
+export abstract class Component<P, S> {
+ constructor(props?: P, context?: any);
+
+ static displayName?: string;
+ static defaultProps?: any;
+ static contextType?: Context<any>;
+
+ // Static members cannot reference class type parameters. This is not
+ // supported in TypeScript. Reusing the same type arguments from `Component`
+ // will lead to an impossible state where one cannot satisfy the type
+ // constraint under no circumstances, see #1356.In general type arguments
+ // seem to be a bit buggy and not supported well at the time of this
+ // writing with TS 3.3.3333.
+ static getDerivedStateFromProps?(
+ props: Readonly<object>,
+ state: Readonly<object>
+ ): object | null;
+ static getDerivedStateFromError?(error: any): object | null;
+
+ state: Readonly<S>;
+ props: RenderableProps<P>;
+ context: any;
+ base?: Element | Text;
+
+ // From https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e836acc75a78cf0655b5dfdbe81d69fdd4d8a252/types/react/index.d.ts#L402
+ // // We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
+ // // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
+ setState<K extends keyof S>(
+ state:
+ | ((
+ prevState: Readonly<S>,
+ props: Readonly<P>
+ ) => Pick<S, K> | Partial<S> | null)
+ | (Pick<S, K> | Partial<S> | null),
+ callback?: () => void
+ ): void;
+
+ forceUpdate(callback?: () => void): void;
+
+ abstract render(
+ props?: RenderableProps<P>,
+ state?: Readonly<S>,
+ context?: any
+ ): ComponentChild;
+}
+
+//
+// Preact createElement
+// -----------------------------------
+
+export function createElement(
+ type: string,
+ props:
+ | (JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any>)
+ | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function createElement<P>(
+ type: ComponentType<P>,
+ props: (Attributes & P) | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export namespace createElement {
+ export import JSX = JSXInternal;
+}
+
+export function h(
+ type: string,
+ props:
+ | (JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any>)
+ | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function h<P>(
+ type: ComponentType<P>,
+ props: (Attributes & P) | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export namespace h {
+ export import JSX = JSXInternal;
+}
+
+//
+// Preact render
+// -----------------------------------
+
+export function render(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment,
+ replaceNode?: Element | Text
+): void;
+export function hydrate(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment
+): void;
+export function cloneElement(
+ vnode: VNode<any>,
+ props?: any,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function cloneElement<P>(
+ vnode: VNode<P>,
+ props?: any,
+ ...children: ComponentChildren[]
+): VNode<P>;
+
+//
+// Preact Built-in Components
+// -----------------------------------
+
+// TODO: Revisit what the public type of this is...
+export const Fragment: ComponentClass<{}, {}>;
+
+//
+// Preact options
+// -----------------------------------
+
+/**
+ * Global options for preact
+ */
+export interface Options {
+ /** Attach a hook that is invoked whenever a VNode is created. */
+ vnode?(vnode: VNode): void;
+ /** Attach a hook that is invoked immediately before a vnode is unmounted. */
+ unmount?(vnode: VNode): void;
+ /** Attach a hook that is invoked after a vnode has rendered. */
+ diffed?(vnode: VNode): void;
+ event?(e: Event): any;
+ requestAnimationFrame?: typeof requestAnimationFrame;
+ debounceRendering?(cb: () => void): void;
+ useDebugValue?(value: string | number): void;
+ _addHookName?(name: string | number): void;
+ __suspenseDidResolve?(vnode: VNode, cb: () => void): void;
+ // __canSuspenseResolve?(vnode: VNode, cb: () => void): void;
+}
+
+export const options: Options;
+
+//
+// Preact helpers
+// -----------------------------------
+export function createRef<T = any>(): RefObject<T>;
+export function toChildArray(
+ children: ComponentChildren
+): Array<VNode | string | number>;
+export function isValidElement(vnode: any): vnode is VNode;
+
+//
+// Context
+// -----------------------------------
+export interface Consumer<T>
+ extends FunctionComponent<{
+ children: (value: T) => ComponentChildren;
+ }> {}
+export interface PreactConsumer<T> extends Consumer<T> {}
+
+export interface Provider<T>
+ extends FunctionComponent<{
+ value: T;
+ children: ComponentChildren;
+ }> {}
+export interface PreactProvider<T> extends Provider<T> {}
+
+export interface Context<T> {
+ Consumer: Consumer<T>;
+ Provider: Provider<T>;
+ displayName?: string;
+}
+export interface PreactContext<T> extends Context<T> {}
+
+export function createContext<T>(defaultValue: T): Context<T>;
diff --git a/preact/src/index.js b/preact/src/index.js
new file mode 100644
index 0000000..ae76ccb
--- /dev/null
+++ b/preact/src/index.js
@@ -0,0 +1,13 @@
+export { render, hydrate } from './render';
+export {
+ createElement,
+ createElement as h,
+ Fragment,
+ createRef,
+ isValidElement
+} from './create-element';
+export { Component } from './component';
+export { cloneElement } from './clone-element';
+export { createContext } from './create-context';
+export { toChildArray } from './diff/children';
+export { default as options } from './options';
diff --git a/preact/src/internal.d.ts b/preact/src/internal.d.ts
new file mode 100644
index 0000000..4592143
--- /dev/null
+++ b/preact/src/internal.d.ts
@@ -0,0 +1,146 @@
+import * as preact from './index';
+
+export enum HookType {
+ useState = 1,
+ useReducer = 2,
+ useEffect = 3,
+ useLayoutEffect = 4,
+ useRef = 5,
+ useImperativeHandle = 6,
+ useMemo = 7,
+ useCallback = 8,
+ useContext = 9,
+ useErrorBoundary = 10,
+ // Not a real hook, but the devtools treat is as such
+ useDebugvalue = 11
+}
+
+export interface DevSource {
+ fileName: string;
+ lineNumber: number;
+}
+
+export interface Options extends preact.Options {
+ /** Attach a hook that is invoked before render, mainly to check the arguments. */
+ _root?(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment
+ ): void;
+ /** Attach a hook that is invoked before a vnode is diffed. */
+ _diff?(vnode: VNode): void;
+ /** Attach a hook that is invoked after a tree was mounted or was updated. */
+ _commit?(vnode: VNode, commitQueue: Component[]): void;
+ /** Attach a hook that is invoked before a vnode has rendered. */
+ _render?(vnode: VNode): void;
+ /** Attach a hook that is invoked before a hook's state is queried. */
+ _hook?(component: Component, index: number, type: HookType): void;
+ /** Bypass effect execution. Currenty only used in devtools for hooks inspection */
+ _skipEffects?: boolean;
+ /** Attach a hook that is invoked after an error is caught in a component but before calling lifecycle hooks */
+ _catchError(error: any, vnode: VNode, oldVNode?: VNode | undefined): void;
+}
+
+export type ComponentChild =
+ | VNode<any>
+ | string
+ | number
+ | boolean
+ | null
+ | undefined;
+export type ComponentChildren = ComponentChild[] | ComponentChild;
+
+export interface FunctionComponent<P = {}> extends preact.FunctionComponent<P> {
+ // Internally, createContext uses `contextType` on a Function component to
+ // implement the Consumer component
+ contextType?: PreactContext;
+
+ // Internally, createContext stores a ref to the context object on the Provider
+ // Function component to help devtools
+ _contextRef?: PreactContext;
+
+ // Define these properties as undefined on FunctionComponent to get rid of
+ // some errors in `diff()`
+ getDerivedStateFromProps?: undefined;
+ getDerivedStateFromError?: undefined;
+}
+
+export interface ComponentClass<P = {}> extends preact.ComponentClass<P> {
+ _contextRef?: any;
+
+ // Override public contextType with internal PreactContext type
+ contextType?: PreactContext;
+}
+
+// Redefine ComponentType using our new internal FunctionComponent interface above
+export type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
+
+export interface PreactElement extends HTMLElement {
+ _children?: VNode<any> | null;
+ /** Event listeners to support event delegation */
+ _listeners?: Record<string, (e: Event) => void>;
+
+ // Preact uses this attribute to detect SVG nodes
+ ownerSVGElement?: SVGElement | null;
+
+ // style: HTMLElement["style"]; // From HTMLElement
+
+ data?: string | number; // From Text node
+}
+
+// We use the `current` property to differentiate between the two kinds of Refs so
+// internally we'll define `current` on both to make TypeScript happy
+type RefObject<T> = { current: T | null };
+type RefCallback<T> = { (instance: T | null): void; current: undefined };
+type Ref<T> = RefObject<T> | RefCallback<T>;
+
+export interface VNode<P = {}> extends preact.VNode<P> {
+ // Redefine type here using our internal ComponentType type
+ type: string | ComponentType<P>;
+ props: P & { children: ComponentChildren };
+ ref?: Ref<any> | null;
+ _children: Array<VNode<any>> | null;
+ _parent: VNode | null;
+ _depth: number | null;
+ /**
+ * The [first (for Fragments)] DOM child of a VNode
+ */
+ _dom: PreactElement | null;
+ /**
+ * The last dom child of a Fragment, or components that return a Fragment
+ */
+ _nextDom: PreactElement | null;
+ _component: Component | null;
+ _hydrating: boolean | null;
+ constructor: undefined;
+ _original: number;
+}
+
+export interface Component<P = {}, S = {}> extends preact.Component<P, S> {
+ // When component is functional component, this is reset to functional component
+ constructor: ComponentType<P>;
+ state: S; // Override Component["state"] to not be readonly for internal use, specifically Hooks
+ base?: PreactElement;
+
+ _dirty: boolean;
+ _force?: boolean;
+ _renderCallbacks: Array<() => void>; // Only class components
+ _globalContext?: any;
+ _vnode?: VNode<P> | null;
+ _nextState?: S | null; // Only class components
+ /** Only used in the devtools to later dirty check if state has changed */
+ _prevState?: S | null;
+ /**
+ * Pointer to the parent dom node. This is only needed for top-level Fragment
+ * components or array returns.
+ */
+ _parentDom?: PreactElement | null;
+ // Always read, set only when handling error
+ _processingException?: Component<any, any> | null;
+ // Always read, set only when handling error. This is used to indicate at diffTime to set _processingException
+ _pendingError?: Component<any, any> | null;
+}
+
+export interface PreactContext extends preact.Context<any> {
+ _id: string;
+ _defaultValue: any;
+}
diff --git a/preact/src/jsx.d.ts b/preact/src/jsx.d.ts
new file mode 100644
index 0000000..7533435
--- /dev/null
+++ b/preact/src/jsx.d.ts
@@ -0,0 +1,974 @@
+// Users who only use Preact for SSR might not specify "dom" in their lib in tsconfig.json
+/// <reference lib="dom" />
+
+import {
+ ClassAttributes,
+ Component,
+ PreactDOMAttributes,
+ VNode
+} from './index';
+
+type Defaultize<Props, Defaults> =
+ // Distribute over unions
+ Props extends any // Make any properties included in Default optional
+ ? Partial<Pick<Props, Extract<keyof Props, keyof Defaults>>> & // Include the remaining properties from Props
+ Pick<Props, Exclude<keyof Props, keyof Defaults>>
+ : never;
+
+export namespace JSXInternal {
+ export type LibraryManagedAttributes<Component, Props> = Component extends {
+ defaultProps: infer Defaults;
+ }
+ ? Defaultize<Props, Defaults>
+ : Props;
+
+ export interface IntrinsicAttributes {
+ key?: any;
+ }
+
+ export interface Element extends VNode<any> {}
+
+ export interface ElementClass extends Component<any, any> {}
+
+ export interface ElementAttributesProperty {
+ props: any;
+ }
+
+ export interface ElementChildrenAttribute {
+ children: any;
+ }
+
+ export type DOMCSSProperties = {
+ [key in keyof Omit<
+ CSSStyleDeclaration,
+ | 'item'
+ | 'setProperty'
+ | 'removeProperty'
+ | 'getPropertyValue'
+ | 'getPropertyPriority'
+ >]?: string | number | null | undefined;
+ };
+ export type AllCSSProperties = {
+ [key: string]: string | number | null | undefined;
+ };
+ export interface CSSProperties extends AllCSSProperties, DOMCSSProperties {
+ cssText?: string | null;
+ }
+
+ export interface SVGAttributes<Target extends EventTarget = SVGElement>
+ extends HTMLAttributes<Target> {
+ accentHeight?: number | string;
+ accumulate?: 'none' | 'sum';
+ additive?: 'replace' | 'sum';
+ alignmentBaseline?:
+ | 'auto'
+ | 'baseline'
+ | 'before-edge'
+ | 'text-before-edge'
+ | 'middle'
+ | 'central'
+ | 'after-edge'
+ | 'text-after-edge'
+ | 'ideographic'
+ | 'alphabetic'
+ | 'hanging'
+ | 'mathematical'
+ | 'inherit';
+ allowReorder?: 'no' | 'yes';
+ alphabetic?: number | string;
+ amplitude?: number | string;
+ arabicForm?: 'initial' | 'medial' | 'terminal' | 'isolated';
+ ascent?: number | string;
+ attributeName?: string;
+ attributeType?: string;
+ autoReverse?: number | string;
+ azimuth?: number | string;
+ baseFrequency?: number | string;
+ baselineShift?: number | string;
+ baseProfile?: number | string;
+ bbox?: number | string;
+ begin?: number | string;
+ bias?: number | string;
+ by?: number | string;
+ calcMode?: number | string;
+ capHeight?: number | string;
+ clip?: number | string;
+ clipPath?: string;
+ clipPathUnits?: number | string;
+ clipRule?: number | string;
+ colorInterpolation?: number | string;
+ colorInterpolationFilters?: 'auto' | 'sRGB' | 'linearRGB' | 'inherit';
+ colorProfile?: number | string;
+ colorRendering?: number | string;
+ contentScriptType?: number | string;
+ contentStyleType?: number | string;
+ cursor?: number | string;
+ cx?: number | string;
+ cy?: number | string;
+ d?: string;
+ decelerate?: number | string;
+ descent?: number | string;
+ diffuseConstant?: number | string;
+ direction?: number | string;
+ display?: number | string;
+ divisor?: number | string;
+ dominantBaseline?: number | string;
+ dur?: number | string;
+ dx?: number | string;
+ dy?: number | string;
+ edgeMode?: number | string;
+ elevation?: number | string;
+ enableBackground?: number | string;
+ end?: number | string;
+ exponent?: number | string;
+ externalResourcesRequired?: number | string;
+ fill?: string;
+ fillOpacity?: number | string;
+ fillRule?: 'nonzero' | 'evenodd' | 'inherit';
+ filter?: string;
+ filterRes?: number | string;
+ filterUnits?: number | string;
+ floodColor?: number | string;
+ floodOpacity?: number | string;
+ focusable?: number | string;
+ fontFamily?: string;
+ fontSize?: number | string;
+ fontSizeAdjust?: number | string;
+ fontStretch?: number | string;
+ fontStyle?: number | string;
+ fontVariant?: number | string;
+ fontWeight?: number | string;
+ format?: number | string;
+ from?: number | string;
+ fx?: number | string;
+ fy?: number | string;
+ g1?: number | string;
+ g2?: number | string;
+ glyphName?: number | string;
+ glyphOrientationHorizontal?: number | string;
+ glyphOrientationVertical?: number | string;
+ glyphRef?: number | string;
+ gradientTransform?: string;
+ gradientUnits?: string;
+ hanging?: number | string;
+ horizAdvX?: number | string;
+ horizOriginX?: number | string;
+ ideographic?: number | string;
+ imageRendering?: number | string;
+ in2?: number | string;
+ in?: string;
+ intercept?: number | string;
+ k1?: number | string;
+ k2?: number | string;
+ k3?: number | string;
+ k4?: number | string;
+ k?: number | string;
+ kernelMatrix?: number | string;
+ kernelUnitLength?: number | string;
+ kerning?: number | string;
+ keyPoints?: number | string;
+ keySplines?: number | string;
+ keyTimes?: number | string;
+ lengthAdjust?: number | string;
+ letterSpacing?: number | string;
+ lightingColor?: number | string;
+ limitingConeAngle?: number | string;
+ local?: number | string;
+ markerEnd?: string;
+ markerHeight?: number | string;
+ markerMid?: string;
+ markerStart?: string;
+ markerUnits?: number | string;
+ markerWidth?: number | string;
+ mask?: string;
+ maskContentUnits?: number | string;
+ maskUnits?: number | string;
+ mathematical?: number | string;
+ mode?: number | string;
+ numOctaves?: number | string;
+ offset?: number | string;
+ opacity?: number | string;
+ operator?: number | string;
+ order?: number | string;
+ orient?: number | string;
+ orientation?: number | string;
+ origin?: number | string;
+ overflow?: number | string;
+ overlinePosition?: number | string;
+ overlineThickness?: number | string;
+ paintOrder?: number | string;
+ panose1?: number | string;
+ pathLength?: number | string;
+ patternContentUnits?: string;
+ patternTransform?: number | string;
+ patternUnits?: string;
+ pointerEvents?: number | string;
+ points?: string;
+ pointsAtX?: number | string;
+ pointsAtY?: number | string;
+ pointsAtZ?: number | string;
+ preserveAlpha?: number | string;
+ preserveAspectRatio?: string;
+ primitiveUnits?: number | string;
+ r?: number | string;
+ radius?: number | string;
+ refX?: number | string;
+ refY?: number | string;
+ renderingIntent?: number | string;
+ repeatCount?: number | string;
+ repeatDur?: number | string;
+ requiredExtensions?: number | string;
+ requiredFeatures?: number | string;
+ restart?: number | string;
+ result?: string;
+ rotate?: number | string;
+ rx?: number | string;
+ ry?: number | string;
+ scale?: number | string;
+ seed?: number | string;
+ shapeRendering?: number | string;
+ slope?: number | string;
+ spacing?: number | string;
+ specularConstant?: number | string;
+ specularExponent?: number | string;
+ speed?: number | string;
+ spreadMethod?: string;
+ startOffset?: number | string;
+ stdDeviation?: number | string;
+ stemh?: number | string;
+ stemv?: number | string;
+ stitchTiles?: number | string;
+ stopColor?: string;
+ stopOpacity?: number | string;
+ strikethroughPosition?: number | string;
+ strikethroughThickness?: number | string;
+ string?: number | string;
+ stroke?: string;
+ strokeDasharray?: string | number;
+ strokeDashoffset?: string | number;
+ strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
+ strokeLinejoin?: 'miter' | 'round' | 'bevel' | 'inherit';
+ strokeMiterlimit?: string | number;
+ strokeOpacity?: number | string;
+ strokeWidth?: number | string;
+ surfaceScale?: number | string;
+ systemLanguage?: number | string;
+ tableValues?: number | string;
+ targetX?: number | string;
+ targetY?: number | string;
+ textAnchor?: string;
+ textDecoration?: number | string;
+ textLength?: number | string;
+ textRendering?: number | string;
+ to?: number | string;
+ transform?: string;
+ u1?: number | string;
+ u2?: number | string;
+ underlinePosition?: number | string;
+ underlineThickness?: number | string;
+ unicode?: number | string;
+ unicodeBidi?: number | string;
+ unicodeRange?: number | string;
+ unitsPerEm?: number | string;
+ vAlphabetic?: number | string;
+ values?: string;
+ vectorEffect?: number | string;
+ version?: string;
+ vertAdvY?: number | string;
+ vertOriginX?: number | string;
+ vertOriginY?: number | string;
+ vHanging?: number | string;
+ vIdeographic?: number | string;
+ viewBox?: string;
+ viewTarget?: number | string;
+ visibility?: number | string;
+ vMathematical?: number | string;
+ widths?: number | string;
+ wordSpacing?: number | string;
+ writingMode?: number | string;
+ x1?: number | string;
+ x2?: number | string;
+ x?: number | string;
+ xChannelSelector?: string;
+ xHeight?: number | string;
+ xlinkActuate?: string;
+ xlinkArcrole?: string;
+ xlinkHref?: string;
+ xlinkRole?: string;
+ xlinkShow?: string;
+ xlinkTitle?: string;
+ xlinkType?: string;
+ xmlBase?: string;
+ xmlLang?: string;
+ xmlns?: string;
+ xmlnsXlink?: string;
+ xmlSpace?: string;
+ y1?: number | string;
+ y2?: number | string;
+ y?: number | string;
+ yChannelSelector?: string;
+ z?: number | string;
+ zoomAndPan?: string;
+ }
+
+ export interface PathAttributes {
+ d: string;
+ }
+
+ export type TargetedEvent<
+ Target extends EventTarget = EventTarget,
+ TypedEvent extends Event = Event
+ > = Omit<TypedEvent, 'currentTarget'> & {
+ readonly currentTarget: Target;
+ };
+
+ export type TargetedAnimationEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, AnimationEvent>;
+ export type TargetedClipboardEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, ClipboardEvent>;
+ export type TargetedCompositionEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, CompositionEvent>;
+ export type TargetedDragEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ DragEvent
+ >;
+ export type TargetedFocusEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ FocusEvent
+ >;
+ export type TargetedKeyboardEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ KeyboardEvent
+ >;
+ export type TargetedMouseEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ MouseEvent
+ >;
+ export type TargetedPointerEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ PointerEvent
+ >;
+ export type TargetedTouchEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ TouchEvent
+ >;
+ export type TargetedTransitionEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, TransitionEvent>;
+ export type TargetedUIEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ UIEvent
+ >;
+ export type TargetedWheelEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ WheelEvent
+ >;
+
+ export interface EventHandler<E extends TargetedEvent> {
+ /**
+ * The `this` keyword always points to the DOM element the event handler
+ * was invoked on. See: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers#Event_handlers_parameters_this_binding_and_the_return_value
+ */
+ (this: never, event: E): void;
+ }
+
+ export type AnimationEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedAnimationEvent<Target>
+ >;
+ export type ClipboardEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedClipboardEvent<Target>
+ >;
+ export type CompositionEventHandler<
+ Target extends EventTarget
+ > = EventHandler<TargetedCompositionEvent<Target>>;
+ export type DragEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedDragEvent<Target>
+ >;
+ export type FocusEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedFocusEvent<Target>
+ >;
+ export type GenericEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedEvent<Target>
+ >;
+ export type KeyboardEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedKeyboardEvent<Target>
+ >;
+ export type MouseEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedMouseEvent<Target>
+ >;
+ export type PointerEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedPointerEvent<Target>
+ >;
+ export type TouchEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedTouchEvent<Target>
+ >;
+ export type TransitionEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedTransitionEvent<Target>
+ >;
+ export type UIEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedUIEvent<Target>
+ >;
+ export type WheelEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedWheelEvent<Target>
+ >;
+
+ export interface DOMAttributes<Target extends EventTarget>
+ extends PreactDOMAttributes {
+ // Image Events
+ onLoad?: GenericEventHandler<Target>;
+ onLoadCapture?: GenericEventHandler<Target>;
+ onError?: GenericEventHandler<Target>;
+ onErrorCapture?: GenericEventHandler<Target>;
+
+ // Clipboard Events
+ onCopy?: ClipboardEventHandler<Target>;
+ onCopyCapture?: ClipboardEventHandler<Target>;
+ onCut?: ClipboardEventHandler<Target>;
+ onCutCapture?: ClipboardEventHandler<Target>;
+ onPaste?: ClipboardEventHandler<Target>;
+ onPasteCapture?: ClipboardEventHandler<Target>;
+
+ // Composition Events
+ onCompositionEnd?: CompositionEventHandler<Target>;
+ onCompositionEndCapture?: CompositionEventHandler<Target>;
+ onCompositionStart?: CompositionEventHandler<Target>;
+ onCompositionStartCapture?: CompositionEventHandler<Target>;
+ onCompositionUpdate?: CompositionEventHandler<Target>;
+ onCompositionUpdateCapture?: CompositionEventHandler<Target>;
+
+ // Details Events
+ onToggle?: GenericEventHandler<Target>;
+
+ // Focus Events
+ onFocus?: FocusEventHandler<Target>;
+ onFocusCapture?: FocusEventHandler<Target>;
+ onBlur?: FocusEventHandler<Target>;
+ onBlurCapture?: FocusEventHandler<Target>;
+
+ // Form Events
+ onChange?: GenericEventHandler<Target>;
+ onChangeCapture?: GenericEventHandler<Target>;
+ onInput?: GenericEventHandler<Target>;
+ onInputCapture?: GenericEventHandler<Target>;
+ onSearch?: GenericEventHandler<Target>;
+ onSearchCapture?: GenericEventHandler<Target>;
+ onSubmit?: GenericEventHandler<Target>;
+ onSubmitCapture?: GenericEventHandler<Target>;
+ onInvalid?: GenericEventHandler<Target>;
+ onInvalidCapture?: GenericEventHandler<Target>;
+ onReset?: GenericEventHandler<Target>;
+ onResetCapture?: GenericEventHandler<Target>;
+ onFormData?: GenericEventHandler<Target>;
+ onFormDataCapture?: GenericEventHandler<Target>;
+
+ // Keyboard Events
+ onKeyDown?: KeyboardEventHandler<Target>;
+ onKeyDownCapture?: KeyboardEventHandler<Target>;
+ onKeyPress?: KeyboardEventHandler<Target>;
+ onKeyPressCapture?: KeyboardEventHandler<Target>;
+ onKeyUp?: KeyboardEventHandler<Target>;
+ onKeyUpCapture?: KeyboardEventHandler<Target>;
+
+ // Media Events
+ onAbort?: GenericEventHandler<Target>;
+ onAbortCapture?: GenericEventHandler<Target>;
+ onCanPlay?: GenericEventHandler<Target>;
+ onCanPlayCapture?: GenericEventHandler<Target>;
+ onCanPlayThrough?: GenericEventHandler<Target>;
+ onCanPlayThroughCapture?: GenericEventHandler<Target>;
+ onDurationChange?: GenericEventHandler<Target>;
+ onDurationChangeCapture?: GenericEventHandler<Target>;
+ onEmptied?: GenericEventHandler<Target>;
+ onEmptiedCapture?: GenericEventHandler<Target>;
+ onEncrypted?: GenericEventHandler<Target>;
+ onEncryptedCapture?: GenericEventHandler<Target>;
+ onEnded?: GenericEventHandler<Target>;
+ onEndedCapture?: GenericEventHandler<Target>;
+ onLoadedData?: GenericEventHandler<Target>;
+ onLoadedDataCapture?: GenericEventHandler<Target>;
+ onLoadedMetadata?: GenericEventHandler<Target>;
+ onLoadedMetadataCapture?: GenericEventHandler<Target>;
+ onLoadStart?: GenericEventHandler<Target>;
+ onLoadStartCapture?: GenericEventHandler<Target>;
+ onPause?: GenericEventHandler<Target>;
+ onPauseCapture?: GenericEventHandler<Target>;
+ onPlay?: GenericEventHandler<Target>;
+ onPlayCapture?: GenericEventHandler<Target>;
+ onPlaying?: GenericEventHandler<Target>;
+ onPlayingCapture?: GenericEventHandler<Target>;
+ onProgress?: GenericEventHandler<Target>;
+ onProgressCapture?: GenericEventHandler<Target>;
+ onRateChange?: GenericEventHandler<Target>;
+ onRateChangeCapture?: GenericEventHandler<Target>;
+ onSeeked?: GenericEventHandler<Target>;
+ onSeekedCapture?: GenericEventHandler<Target>;
+ onSeeking?: GenericEventHandler<Target>;
+ onSeekingCapture?: GenericEventHandler<Target>;
+ onStalled?: GenericEventHandler<Target>;
+ onStalledCapture?: GenericEventHandler<Target>;
+ onSuspend?: GenericEventHandler<Target>;
+ onSuspendCapture?: GenericEventHandler<Target>;
+ onTimeUpdate?: GenericEventHandler<Target>;
+ onTimeUpdateCapture?: GenericEventHandler<Target>;
+ onVolumeChange?: GenericEventHandler<Target>;
+ onVolumeChangeCapture?: GenericEventHandler<Target>;
+ onWaiting?: GenericEventHandler<Target>;
+ onWaitingCapture?: GenericEventHandler<Target>;
+
+ // MouseEvents
+ onClick?: MouseEventHandler<Target>;
+ onClickCapture?: MouseEventHandler<Target>;
+ onContextMenu?: MouseEventHandler<Target>;
+ onContextMenuCapture?: MouseEventHandler<Target>;
+ onDblClick?: MouseEventHandler<Target>;
+ onDblClickCapture?: MouseEventHandler<Target>;
+ onDrag?: DragEventHandler<Target>;
+ onDragCapture?: DragEventHandler<Target>;
+ onDragEnd?: DragEventHandler<Target>;
+ onDragEndCapture?: DragEventHandler<Target>;
+ onDragEnter?: DragEventHandler<Target>;
+ onDragEnterCapture?: DragEventHandler<Target>;
+ onDragExit?: DragEventHandler<Target>;
+ onDragExitCapture?: DragEventHandler<Target>;
+ onDragLeave?: DragEventHandler<Target>;
+ onDragLeaveCapture?: DragEventHandler<Target>;
+ onDragOver?: DragEventHandler<Target>;
+ onDragOverCapture?: DragEventHandler<Target>;
+ onDragStart?: DragEventHandler<Target>;
+ onDragStartCapture?: DragEventHandler<Target>;
+ onDrop?: DragEventHandler<Target>;
+ onDropCapture?: DragEventHandler<Target>;
+ onMouseDown?: MouseEventHandler<Target>;
+ onMouseDownCapture?: MouseEventHandler<Target>;
+ onMouseEnter?: MouseEventHandler<Target>;
+ onMouseEnterCapture?: MouseEventHandler<Target>;
+ onMouseLeave?: MouseEventHandler<Target>;
+ onMouseLeaveCapture?: MouseEventHandler<Target>;
+ onMouseMove?: MouseEventHandler<Target>;
+ onMouseMoveCapture?: MouseEventHandler<Target>;
+ onMouseOut?: MouseEventHandler<Target>;
+ onMouseOutCapture?: MouseEventHandler<Target>;
+ onMouseOver?: MouseEventHandler<Target>;
+ onMouseOverCapture?: MouseEventHandler<Target>;
+ onMouseUp?: MouseEventHandler<Target>;
+ onMouseUpCapture?: MouseEventHandler<Target>;
+
+ // Selection Events
+ onSelect?: GenericEventHandler<Target>;
+ onSelectCapture?: GenericEventHandler<Target>;
+
+ // Touch Events
+ onTouchCancel?: TouchEventHandler<Target>;
+ onTouchCancelCapture?: TouchEventHandler<Target>;
+ onTouchEnd?: TouchEventHandler<Target>;
+ onTouchEndCapture?: TouchEventHandler<Target>;
+ onTouchMove?: TouchEventHandler<Target>;
+ onTouchMoveCapture?: TouchEventHandler<Target>;
+ onTouchStart?: TouchEventHandler<Target>;
+ onTouchStartCapture?: TouchEventHandler<Target>;
+
+ // Pointer Events
+ onPointerOver?: PointerEventHandler<Target>;
+ onPointerOverCapture?: PointerEventHandler<Target>;
+ onPointerEnter?: PointerEventHandler<Target>;
+ onPointerEnterCapture?: PointerEventHandler<Target>;
+ onPointerDown?: PointerEventHandler<Target>;
+ onPointerDownCapture?: PointerEventHandler<Target>;
+ onPointerMove?: PointerEventHandler<Target>;
+ onPointerMoveCapture?: PointerEventHandler<Target>;
+ onPointerUp?: PointerEventHandler<Target>;
+ onPointerUpCapture?: PointerEventHandler<Target>;
+ onPointerCancel?: PointerEventHandler<Target>;
+ onPointerCancelCapture?: PointerEventHandler<Target>;
+ onPointerOut?: PointerEventHandler<Target>;
+ onPointerOutCapture?: PointerEventHandler<Target>;
+ onPointerLeave?: PointerEventHandler<Target>;
+ onPointerLeaveCapture?: PointerEventHandler<Target>;
+ onGotPointerCapture?: PointerEventHandler<Target>;
+ onGotPointerCaptureCapture?: PointerEventHandler<Target>;
+ onLostPointerCapture?: PointerEventHandler<Target>;
+ onLostPointerCaptureCapture?: PointerEventHandler<Target>;
+
+ // UI Events
+ onScroll?: UIEventHandler<Target>;
+ onScrollCapture?: UIEventHandler<Target>;
+
+ // Wheel Events
+ onWheel?: WheelEventHandler<Target>;
+ onWheelCapture?: WheelEventHandler<Target>;
+
+ // Animation Events
+ onAnimationStart?: AnimationEventHandler<Target>;
+ onAnimationStartCapture?: AnimationEventHandler<Target>;
+ onAnimationEnd?: AnimationEventHandler<Target>;
+ onAnimationEndCapture?: AnimationEventHandler<Target>;
+ onAnimationIteration?: AnimationEventHandler<Target>;
+ onAnimationIterationCapture?: AnimationEventHandler<Target>;
+
+ // Transition Events
+ onTransitionEnd?: TransitionEventHandler<Target>;
+ onTransitionEndCapture?: TransitionEventHandler<Target>;
+ }
+
+ export interface HTMLAttributes<RefType extends EventTarget = EventTarget>
+ extends ClassAttributes<RefType>,
+ DOMAttributes<RefType> {
+ // Standard HTML Attributes
+ accept?: string;
+ acceptCharset?: string;
+ accessKey?: string;
+ action?: string;
+ allowFullScreen?: boolean;
+ allowTransparency?: boolean;
+ alt?: string;
+ as?: string;
+ async?: boolean;
+ autocomplete?: string;
+ autoComplete?: string;
+ autocorrect?: string;
+ autoCorrect?: string;
+ autofocus?: boolean;
+ autoFocus?: boolean;
+ autoPlay?: boolean;
+ capture?: boolean | string;
+ cellPadding?: number | string;
+ cellSpacing?: number | string;
+ charSet?: string;
+ challenge?: string;
+ checked?: boolean;
+ class?: string;
+ className?: string;
+ cols?: number;
+ colSpan?: number;
+ content?: string;
+ contentEditable?: boolean;
+ contextMenu?: string;
+ controls?: boolean;
+ controlsList?: string;
+ coords?: string;
+ crossOrigin?: string;
+ data?: string;
+ dateTime?: string;
+ default?: boolean;
+ defer?: boolean;
+ dir?: 'auto' | 'rtl' | 'ltr';
+ disabled?: boolean;
+ disableRemotePlayback?: boolean;
+ download?: any;
+ decoding?: 'sync' | 'async' | 'auto';
+ draggable?: boolean;
+ encType?: string;
+ form?: string;
+ formAction?: string;
+ formEncType?: string;
+ formMethod?: string;
+ formNoValidate?: boolean;
+ formTarget?: string;
+ frameBorder?: number | string;
+ headers?: string;
+ height?: number | string;
+ hidden?: boolean;
+ high?: number;
+ href?: string;
+ hrefLang?: string;
+ for?: string;
+ htmlFor?: string;
+ httpEquiv?: string;
+ icon?: string;
+ id?: string;
+ inputMode?: string;
+ integrity?: string;
+ is?: string;
+ keyParams?: string;
+ keyType?: string;
+ kind?: string;
+ label?: string;
+ lang?: string;
+ list?: string;
+ loading?: 'eager' | 'lazy';
+ loop?: boolean;
+ low?: number;
+ manifest?: string;
+ marginHeight?: number;
+ marginWidth?: number;
+ max?: number | string;
+ maxLength?: number;
+ media?: string;
+ mediaGroup?: string;
+ method?: string;
+ min?: number | string;
+ minLength?: number;
+ multiple?: boolean;
+ muted?: boolean;
+ name?: string;
+ nonce?: string;
+ noValidate?: boolean;
+ open?: boolean;
+ optimum?: number;
+ pattern?: string;
+ placeholder?: string;
+ playsInline?: boolean;
+ poster?: string;
+ preload?: string;
+ radioGroup?: string;
+ readonly?: boolean;
+ readOnly?: boolean;
+ rel?: string;
+ required?: boolean;
+ role?: string;
+ rows?: number;
+ rowSpan?: number;
+ sandbox?: string;
+ scope?: string;
+ scoped?: boolean;
+ scrolling?: string;
+ seamless?: boolean;
+ selected?: boolean;
+ shape?: string;
+ size?: number;
+ sizes?: string;
+ slot?: string;
+ span?: number;
+ spellcheck?: boolean;
+ spellCheck?: boolean;
+ src?: string;
+ srcset?: string;
+ srcDoc?: string;
+ srcLang?: string;
+ srcSet?: string;
+ start?: number;
+ step?: number | string;
+ style?: string | CSSProperties;
+ summary?: string;
+ tabIndex?: number;
+ target?: string;
+ title?: string;
+ type?: string;
+ useMap?: string;
+ value?: string | string[] | number;
+ volume?: string | number;
+ width?: number | string;
+ wmode?: string;
+ wrap?: string;
+
+ // Non-standard Attributes
+ autocapitalize?:
+ | 'off'
+ | 'none'
+ | 'on'
+ | 'sentences'
+ | 'words'
+ | 'characters';
+ autoCapitalize?:
+ | 'off'
+ | 'none'
+ | 'on'
+ | 'sentences'
+ | 'words'
+ | 'characters';
+
+ // RDFa Attributes
+ about?: string;
+ datatype?: string;
+ inlist?: any;
+ prefix?: string;
+ property?: string;
+ resource?: string;
+ typeof?: string;
+ vocab?: string;
+
+ // Microdata Attributes
+ itemProp?: string;
+ itemScope?: boolean;
+ itemType?: string;
+ itemID?: string;
+ itemRef?: string;
+ }
+
+ export interface HTMLMarqueeElement extends HTMLElement {
+ behavior?: 'scroll' | 'slide' | 'alternate';
+ bgColor?: string;
+ direction?: 'left' | 'right' | 'up' | 'down';
+ height?: number | string;
+ hspace?: number | string;
+ loop?: number | string;
+ scrollAmount?: number | string;
+ scrollDelay?: number | string;
+ trueSpeed?: boolean;
+ vspace?: number | string;
+ width?: number | string;
+ }
+
+ export interface IntrinsicElements {
+ // HTML
+ a: HTMLAttributes<HTMLAnchorElement>;
+ abbr: HTMLAttributes<HTMLElement>;
+ address: HTMLAttributes<HTMLElement>;
+ area: HTMLAttributes<HTMLAreaElement>;
+ article: HTMLAttributes<HTMLElement>;
+ aside: HTMLAttributes<HTMLElement>;
+ audio: HTMLAttributes<HTMLAudioElement>;
+ b: HTMLAttributes<HTMLElement>;
+ base: HTMLAttributes<HTMLBaseElement>;
+ bdi: HTMLAttributes<HTMLElement>;
+ bdo: HTMLAttributes<HTMLElement>;
+ big: HTMLAttributes<HTMLElement>;
+ blockquote: HTMLAttributes<HTMLQuoteElement>;
+ body: HTMLAttributes<HTMLBodyElement>;
+ br: HTMLAttributes<HTMLBRElement>;
+ button: HTMLAttributes<HTMLButtonElement>;
+ canvas: HTMLAttributes<HTMLCanvasElement>;
+ caption: HTMLAttributes<HTMLTableCaptionElement>;
+ cite: HTMLAttributes<HTMLElement>;
+ code: HTMLAttributes<HTMLElement>;
+ col: HTMLAttributes<HTMLTableColElement>;
+ colgroup: HTMLAttributes<HTMLTableColElement>;
+ data: HTMLAttributes<HTMLDataElement>;
+ datalist: HTMLAttributes<HTMLDataListElement>;
+ dd: HTMLAttributes<HTMLElement>;
+ del: HTMLAttributes<HTMLModElement>;
+ details: HTMLAttributes<HTMLDetailsElement>;
+ dfn: HTMLAttributes<HTMLElement>;
+ dialog: HTMLAttributes<HTMLDialogElement>;
+ div: HTMLAttributes<HTMLDivElement>;
+ dl: HTMLAttributes<HTMLDListElement>;
+ dt: HTMLAttributes<HTMLElement>;
+ em: HTMLAttributes<HTMLElement>;
+ embed: HTMLAttributes<HTMLEmbedElement>;
+ fieldset: HTMLAttributes<HTMLFieldSetElement>;
+ figcaption: HTMLAttributes<HTMLElement>;
+ figure: HTMLAttributes<HTMLElement>;
+ footer: HTMLAttributes<HTMLElement>;
+ form: HTMLAttributes<HTMLFormElement>;
+ h1: HTMLAttributes<HTMLHeadingElement>;
+ h2: HTMLAttributes<HTMLHeadingElement>;
+ h3: HTMLAttributes<HTMLHeadingElement>;
+ h4: HTMLAttributes<HTMLHeadingElement>;
+ h5: HTMLAttributes<HTMLHeadingElement>;
+ h6: HTMLAttributes<HTMLHeadingElement>;
+ head: HTMLAttributes<HTMLHeadElement>;
+ header: HTMLAttributes<HTMLElement>;
+ hgroup: HTMLAttributes<HTMLElement>;
+ hr: HTMLAttributes<HTMLHRElement>;
+ html: HTMLAttributes<HTMLHtmlElement>;
+ i: HTMLAttributes<HTMLElement>;
+ iframe: HTMLAttributes<HTMLIFrameElement>;
+ img: HTMLAttributes<HTMLImageElement>;
+ input: HTMLAttributes<HTMLInputElement>;
+ ins: HTMLAttributes<HTMLModElement>;
+ kbd: HTMLAttributes<HTMLElement>;
+ keygen: HTMLAttributes<HTMLUnknownElement>;
+ label: HTMLAttributes<HTMLLabelElement>;
+ legend: HTMLAttributes<HTMLLegendElement>;
+ li: HTMLAttributes<HTMLLIElement>;
+ link: HTMLAttributes<HTMLLinkElement>;
+ main: HTMLAttributes<HTMLElement>;
+ map: HTMLAttributes<HTMLMapElement>;
+ mark: HTMLAttributes<HTMLElement>;
+ marquee: HTMLAttributes<HTMLMarqueeElement>;
+ menu: HTMLAttributes<HTMLMenuElement>;
+ menuitem: HTMLAttributes<HTMLUnknownElement>;
+ meta: HTMLAttributes<HTMLMetaElement>;
+ meter: HTMLAttributes<HTMLMeterElement>;
+ nav: HTMLAttributes<HTMLElement>;
+ noscript: HTMLAttributes<HTMLElement>;
+ object: HTMLAttributes<HTMLObjectElement>;
+ ol: HTMLAttributes<HTMLOListElement>;
+ optgroup: HTMLAttributes<HTMLOptGroupElement>;
+ option: HTMLAttributes<HTMLOptionElement>;
+ output: HTMLAttributes<HTMLOutputElement>;
+ p: HTMLAttributes<HTMLParagraphElement>;
+ param: HTMLAttributes<HTMLParamElement>;
+ picture: HTMLAttributes<HTMLPictureElement>;
+ pre: HTMLAttributes<HTMLPreElement>;
+ progress: HTMLAttributes<HTMLProgressElement>;
+ q: HTMLAttributes<HTMLQuoteElement>;
+ rp: HTMLAttributes<HTMLElement>;
+ rt: HTMLAttributes<HTMLElement>;
+ ruby: HTMLAttributes<HTMLElement>;
+ s: HTMLAttributes<HTMLElement>;
+ samp: HTMLAttributes<HTMLElement>;
+ script: HTMLAttributes<HTMLScriptElement>;
+ section: HTMLAttributes<HTMLElement>;
+ select: HTMLAttributes<HTMLSelectElement>;
+ slot: HTMLAttributes<HTMLSlotElement>;
+ small: HTMLAttributes<HTMLElement>;
+ source: HTMLAttributes<HTMLSourceElement>;
+ span: HTMLAttributes<HTMLSpanElement>;
+ strong: HTMLAttributes<HTMLElement>;
+ style: HTMLAttributes<HTMLStyleElement>;
+ sub: HTMLAttributes<HTMLElement>;
+ summary: HTMLAttributes<HTMLElement>;
+ sup: HTMLAttributes<HTMLElement>;
+ table: HTMLAttributes<HTMLTableElement>;
+ tbody: HTMLAttributes<HTMLTableSectionElement>;
+ td: HTMLAttributes<HTMLTableCellElement>;
+ textarea: HTMLAttributes<HTMLTextAreaElement>;
+ tfoot: HTMLAttributes<HTMLTableSectionElement>;
+ th: HTMLAttributes<HTMLTableCellElement>;
+ thead: HTMLAttributes<HTMLTableSectionElement>;
+ time: HTMLAttributes<HTMLTimeElement>;
+ title: HTMLAttributes<HTMLTitleElement>;
+ tr: HTMLAttributes<HTMLTableRowElement>;
+ track: HTMLAttributes<HTMLTrackElement>;
+ u: HTMLAttributes<HTMLElement>;
+ ul: HTMLAttributes<HTMLUListElement>;
+ var: HTMLAttributes<HTMLElement>;
+ video: HTMLAttributes<HTMLVideoElement>;
+ wbr: HTMLAttributes<HTMLElement>;
+
+ //SVG
+ svg: SVGAttributes<SVGSVGElement>;
+ animate: SVGAttributes<SVGAnimateElement>;
+ circle: SVGAttributes<SVGCircleElement>;
+ animateTransform: SVGAttributes<SVGAnimateElement>;
+ clipPath: SVGAttributes<SVGClipPathElement>;
+ defs: SVGAttributes<SVGDefsElement>;
+ desc: SVGAttributes<SVGDescElement>;
+ ellipse: SVGAttributes<SVGEllipseElement>;
+ feBlend: SVGAttributes<SVGFEBlendElement>;
+ feColorMatrix: SVGAttributes<SVGFEColorMatrixElement>;
+ feComponentTransfer: SVGAttributes<SVGFEComponentTransferElement>;
+ feComposite: SVGAttributes<SVGFECompositeElement>;
+ feConvolveMatrix: SVGAttributes<SVGFEConvolveMatrixElement>;
+ feDiffuseLighting: SVGAttributes<SVGFEDiffuseLightingElement>;
+ feDisplacementMap: SVGAttributes<SVGFEDisplacementMapElement>;
+ feDropShadow: SVGAttributes<SVGFEDropShadowElement>;
+ feFlood: SVGAttributes<SVGFEFloodElement>;
+ feFuncA: SVGAttributes<SVGFEFuncAElement>;
+ feFuncB: SVGAttributes<SVGFEFuncBElement>;
+ feFuncG: SVGAttributes<SVGFEFuncGElement>;
+ feFuncR: SVGAttributes<SVGFEFuncRElement>;
+ feGaussianBlur: SVGAttributes<SVGFEGaussianBlurElement>;
+ feImage: SVGAttributes<SVGFEImageElement>;
+ feMerge: SVGAttributes<SVGFEMergeElement>;
+ feMergeNode: SVGAttributes<SVGFEMergeNodeElement>;
+ feMorphology: SVGAttributes<SVGFEMorphologyElement>;
+ feOffset: SVGAttributes<SVGFEOffsetElement>;
+ feSpecularLighting: SVGAttributes<SVGFESpecularLightingElement>;
+ feTile: SVGAttributes<SVGFETileElement>;
+ feTurbulence: SVGAttributes<SVGFETurbulenceElement>;
+ filter: SVGAttributes<SVGFilterElement>;
+ foreignObject: SVGAttributes<SVGForeignObjectElement>;
+ g: SVGAttributes<SVGGElement>;
+ image: SVGAttributes<SVGImageElement>;
+ line: SVGAttributes<SVGLineElement>;
+ linearGradient: SVGAttributes<SVGLinearGradientElement>;
+ marker: SVGAttributes<SVGMarkerElement>;
+ mask: SVGAttributes<SVGMaskElement>;
+ path: SVGAttributes<SVGPathElement>;
+ pattern: SVGAttributes<SVGPatternElement>;
+ polygon: SVGAttributes<SVGPolygonElement>;
+ polyline: SVGAttributes<SVGPolylineElement>;
+ radialGradient: SVGAttributes<SVGRadialGradientElement>;
+ rect: SVGAttributes<SVGRectElement>;
+ stop: SVGAttributes<SVGStopElement>;
+ symbol: SVGAttributes<SVGSymbolElement>;
+ text: SVGAttributes<SVGTextElement>;
+ tspan: SVGAttributes<SVGTSpanElement>;
+ use: SVGAttributes<SVGUseElement>;
+ }
+}
diff --git a/preact/src/options.js b/preact/src/options.js
new file mode 100644
index 0000000..174f322
--- /dev/null
+++ b/preact/src/options.js
@@ -0,0 +1,16 @@
+import { _catchError } from './diff/catch-error';
+
+/**
+ * The `option` object can potentially contain callback functions
+ * that are called during various stages of our renderer. This is the
+ * foundation on which all our addons like `preact/debug`, `preact/compat`,
+ * and `preact/hooks` are based on. See the `Options` type in `internal.d.ts`
+ * for a full list of available option hooks (most editors/IDEs allow you to
+ * ctrl+click or cmd+click on mac the type definition below).
+ * @type {import('./internal').Options}
+ */
+const options = {
+ _catchError
+};
+
+export default options;
diff --git a/preact/src/render.js b/preact/src/render.js
new file mode 100644
index 0000000..c8ef828
--- /dev/null
+++ b/preact/src/render.js
@@ -0,0 +1,75 @@
+import { EMPTY_OBJ } from './constants';
+import { commitRoot, diff } from './diff/index';
+import { createElement, Fragment } from './create-element';
+import options from './options';
+import { slice } from './util';
+
+/**
+ * Render a Preact virtual node into a DOM element
+ * @param {import('./internal').ComponentChild} vnode The virtual node to render
+ * @param {import('./internal').PreactElement} parentDom The DOM element to
+ * render into
+ * @param {import('./internal').PreactElement | object} [replaceNode] Optional: Attempt to re-use an
+ * existing DOM tree rooted at `replaceNode`
+ */
+export function render(vnode, parentDom, replaceNode) {
+ if (options._root) options._root(vnode, parentDom);
+
+ // We abuse the `replaceNode` parameter in `hydrate()` to signal if we are in
+ // hydration mode or not by passing the `hydrate` function instead of a DOM
+ // element..
+ let isHydrating = typeof replaceNode === 'function';
+
+ // To be able to support calling `render()` multiple times on the same
+ // DOM node, we need to obtain a reference to the previous tree. We do
+ // this by assigning a new `_children` property to DOM nodes which points
+ // to the last rendered tree. By default this property is not present, which
+ // means that we are mounting a new tree for the first time.
+ let oldVNode = isHydrating
+ ? null
+ : (replaceNode && replaceNode._children) || parentDom._children;
+
+ vnode = (
+ (!isHydrating && replaceNode) ||
+ parentDom
+ )._children = createElement(Fragment, null, [vnode]);
+
+ // List of effects that need to be called after diffing.
+ let commitQueue = [];
+ diff(
+ parentDom,
+ // Determine the new vnode tree and store it on the DOM element on
+ // our custom `_children` property.
+ vnode,
+ oldVNode || EMPTY_OBJ,
+ EMPTY_OBJ,
+ parentDom.ownerSVGElement !== undefined,
+ !isHydrating && replaceNode
+ ? [replaceNode]
+ : oldVNode
+ ? null
+ : parentDom.firstChild
+ ? slice.call(parentDom.childNodes)
+ : null,
+ commitQueue,
+ !isHydrating && replaceNode
+ ? replaceNode
+ : oldVNode
+ ? oldVNode._dom
+ : parentDom.firstChild,
+ isHydrating
+ );
+
+ // Flush all queued effects
+ commitRoot(commitQueue, vnode);
+}
+
+/**
+ * Update an existing DOM element with data from a Preact virtual node
+ * @param {import('./internal').ComponentChild} vnode The virtual node to render
+ * @param {import('./internal').PreactElement} parentDom The DOM element to
+ * update
+ */
+export function hydrate(vnode, parentDom) {
+ render(vnode, parentDom, hydrate);
+}
diff --git a/preact/src/util.js b/preact/src/util.js
new file mode 100644
index 0000000..0e9b3b1
--- /dev/null
+++ b/preact/src/util.js
@@ -0,0 +1,27 @@
+import { EMPTY_ARR } from './constants';
+
+/**
+ * Assign properties from `props` to `obj`
+ * @template O, P The obj and props types
+ * @param {O} obj The object to copy properties to
+ * @param {P} props The object to copy properties from
+ * @returns {O & P}
+ */
+export function assign(obj, props) {
+ // @ts-ignore We change the type of `obj` to be `O & P`
+ for (let i in props) obj[i] = props[i];
+ return /** @type {O & P} */ (obj);
+}
+
+/**
+ * Remove a child node from its parent if attached. This is a workaround for
+ * IE11 which doesn't support `Element.prototype.remove()`. Using this function
+ * is smaller than including a dedicated polyfill.
+ * @param {Node} node The node to remove
+ */
+export function removeNode(node) {
+ let parentNode = node.parentNode;
+ if (parentNode) parentNode.removeChild(node);
+}
+
+export const slice = EMPTY_ARR.slice;