summaryrefslogtreecommitdiff
path: root/thirdparty/preact/devtools/devtools.js
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/preact/devtools/devtools.js')
-rw-r--r--thirdparty/preact/devtools/devtools.js427
1 files changed, 0 insertions, 427 deletions
diff --git a/thirdparty/preact/devtools/devtools.js b/thirdparty/preact/devtools/devtools.js
deleted file mode 100644
index 4bcbeae1e..000000000
--- a/thirdparty/preact/devtools/devtools.js
+++ /dev/null
@@ -1,427 +0,0 @@
-/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
-
-import { options, Component } from 'preact';
-
-// Internal helpers from preact
-import { ATTR_KEY } from '../src/constants';
-import { isFunctionalComponent } from '../src/vdom/functional-component';
-
-/**
- * Return a ReactElement-compatible object for the current state of a preact
- * component.
- */
-function createReactElement(component) {
- return {
- type: component.constructor,
- key: component.key,
- ref: null, // Unsupported
- props: component.props
- };
-}
-
-/**
- * Create a ReactDOMComponent-compatible object for a given DOM node rendered
- * by preact.
- *
- * This implements the subset of the ReactDOMComponent interface that
- * React DevTools requires in order to display DOM nodes in the inspector with
- * the correct type and properties.
- *
- * @param {Node} node
- */
-function createReactDOMComponent(node) {
- const childNodes = node.nodeType === Node.ELEMENT_NODE ?
- Array.from(node.childNodes) : [];
-
- const isText = node.nodeType === Node.TEXT_NODE;
-
- return {
- // --- ReactDOMComponent interface
- _currentElement: isText ? node.textContent : {
- type: node.nodeName.toLowerCase(),
- props: node[ATTR_KEY]
- },
- _renderedChildren: childNodes.map(child => {
- if (child._component) {
- return updateReactComponent(child._component);
- }
- return updateReactComponent(child);
- }),
- _stringText: isText ? node.textContent : null,
-
- // --- Additional properties used by preact devtools
-
- // A flag indicating whether the devtools have been notified about the
- // existence of this component instance yet.
- // This is used to send the appropriate notifications when DOM components
- // are added or updated between composite component updates.
- _inDevTools: false,
- node
- };
-}
-
-/**
- * Return the name of a component created by a `ReactElement`-like object.
- *
- * @param {ReactElement} element
- */
-function typeName(element) {
- if (typeof element.type === 'function') {
- return element.type.displayName || element.type.name;
- }
- return element.type;
-}
-
-/**
- * Return a ReactCompositeComponent-compatible object for a given preact
- * component instance.
- *
- * This implements the subset of the ReactCompositeComponent interface that
- * the DevTools requires in order to walk the component tree and inspect the
- * component's properties.
- *
- * See https://github.com/facebook/react-devtools/blob/e31ec5825342eda570acfc9bcb43a44258fceb28/backend/getData.js
- */
-function createReactCompositeComponent(component) {
- const _currentElement = createReactElement(component);
- const node = component.base;
-
- let instance = {
- // --- ReactDOMComponent properties
- getName() {
- return typeName(_currentElement);
- },
- _currentElement: createReactElement(component),
- props: component.props,
- state: component.state,
- forceUpdate: component.forceUpdate.bind(component),
- setState: component.setState.bind(component),
-
- // --- Additional properties used by preact devtools
- node
- };
-
- // React DevTools exposes the `_instance` field of the selected item in the
- // component tree as `$r` in the console. `_instance` must refer to a
- // React Component (or compatible) class instance with `props` and `state`
- // fields and `setState()`, `forceUpdate()` methods.
- instance._instance = component;
-
- // If the root node returned by this component instance's render function
- // was itself a composite component, there will be a `_component` property
- // containing the child component instance.
- if (component._component) {
- instance._renderedComponent = updateReactComponent(component._component);
- } else {
- // Otherwise, if the render() function returned an HTML/SVG element,
- // create a ReactDOMComponent-like object for the DOM node itself.
- instance._renderedComponent = updateReactComponent(node);
- }
-
- return instance;
-}
-
-/**
- * Map of Component|Node to ReactDOMComponent|ReactCompositeComponent-like
- * object.
- *
- * The same React*Component instance must be used when notifying devtools
- * about the initial mount of a component and subsequent updates.
- */
-let instanceMap = new Map();
-
-/**
- * Update (and create if necessary) the ReactDOMComponent|ReactCompositeComponent-like
- * instance for a given preact component instance or DOM Node.
- *
- * @param {Component|Node} componentOrNode
- */
-function updateReactComponent(componentOrNode) {
- const newInstance = componentOrNode instanceof Node ?
- createReactDOMComponent(componentOrNode) :
- createReactCompositeComponent(componentOrNode);
- if (instanceMap.has(componentOrNode)) {
- let inst = instanceMap.get(componentOrNode);
- Object.assign(inst, newInstance);
- return inst;
- }
- instanceMap.set(componentOrNode, newInstance);
- return newInstance;
-}
-
-function nextRootKey(roots) {
- return '.' + Object.keys(roots).length;
-}
-
-/**
- * Find all root component instances rendered by preact in `node`'s children
- * and add them to the `roots` map.
- *
- * @param {DOMElement} node
- * @param {[key: string] => ReactDOMComponent|ReactCompositeComponent}
- */
-function findRoots(node, roots) {
- Array.from(node.childNodes).forEach(child => {
- if (child._component) {
- roots[nextRootKey(roots)] = updateReactComponent(child._component);
- } else {
- findRoots(child, roots);
- }
- });
-}
-
-/**
- * Map of functional component name -> wrapper class.
- */
-let functionalComponentWrappers = new Map();
-
-/**
- * Wrap a functional component with a stateful component.
- *
- * preact does not record any information about the original hierarchy of
- * functional components in the rendered DOM nodes. Wrapping functional components
- * with a trivial wrapper allows us to recover information about the original
- * component structure from the DOM.
- *
- * @param {VNode} vnode
- */
-function wrapFunctionalComponent(vnode) {
- const originalRender = vnode.nodeName;
- const name = vnode.nodeName.name || '(Function.name missing)';
- const wrappers = functionalComponentWrappers;
- if (!wrappers.has(originalRender)) {
- let wrapper = class extends Component {
- render(props, state, context) {
- return originalRender(props, context);
- }
- };
-
- // Expose the original component name. React Dev Tools will use
- // this property if it exists or fall back to Function.name
- // otherwise.
- wrapper.displayName = name;
-
- wrappers.set(originalRender, wrapper);
- }
- vnode.nodeName = wrappers.get(originalRender);
-}
-
-/**
- * Create a bridge for exposing preact's component tree to React DevTools.
- *
- * It creates implementations of the interfaces that ReactDOM passes to
- * devtools to enable it to query the component tree and hook into component
- * updates.
- *
- * See https://github.com/facebook/react/blob/59ff7749eda0cd858d5ee568315bcba1be75a1ca/src/renderers/dom/ReactDOM.js
- * for how ReactDOM exports its internals for use by the devtools and
- * the `attachRenderer()` function in
- * https://github.com/facebook/react-devtools/blob/e31ec5825342eda570acfc9bcb43a44258fceb28/backend/attachRenderer.js
- * for how the devtools consumes the resulting objects.
- */
-function createDevToolsBridge() {
- // The devtools has different paths for interacting with the renderers from
- // React Native, legacy React DOM and current React DOM.
- //
- // Here we emulate the interface for the current React DOM (v15+) lib.
-
- // ReactDOMComponentTree-like object
- const ComponentTree = {
- getNodeFromInstance(instance) {
- return instance.node;
- },
- getClosestInstanceFromNode(node) {
- while (node && !node._component) {
- node = node.parentNode;
- }
- return node ? updateReactComponent(node._component) : null;
- }
- };
-
- // Map of root ID (the ID is unimportant) to component instance.
- let roots = {};
- findRoots(document.body, roots);
-
- // ReactMount-like object
- //
- // Used by devtools to discover the list of root component instances and get
- // notified when new root components are rendered.
- const Mount = {
- _instancesByReactRootID: roots,
-
- // Stub - React DevTools expects to find this method and replace it
- // with a wrapper in order to observe new root components being added
- _renderNewRootComponent(/* instance, ... */) { }
- };
-
- // ReactReconciler-like object
- const Reconciler = {
- // Stubs - React DevTools expects to find these methods and replace them
- // with wrappers in order to observe components being mounted, updated and
- // unmounted
- mountComponent(/* instance, ... */) { },
- performUpdateIfNecessary(/* instance, ... */) { },
- receiveComponent(/* instance, ... */) { },
- unmountComponent(/* instance, ... */) { }
- };
-
- /** Notify devtools that a new component instance has been mounted into the DOM. */
- const componentAdded = component => {
- const instance = updateReactComponent(component);
- if (isRootComponent(component)) {
- instance._rootID = nextRootKey(roots);
- roots[instance._rootID] = instance;
- Mount._renderNewRootComponent(instance);
- }
- visitNonCompositeChildren(instance, childInst => {
- childInst._inDevTools = true;
- Reconciler.mountComponent(childInst);
- });
- Reconciler.mountComponent(instance);
- };
-
- /** Notify devtools that a component has been updated with new props/state. */
- const componentUpdated = component => {
- const prevRenderedChildren = [];
- visitNonCompositeChildren(instanceMap.get(component), childInst => {
- prevRenderedChildren.push(childInst);
- });
-
- // Notify devtools about updates to this component and any non-composite
- // children
- const instance = updateReactComponent(component);
- Reconciler.receiveComponent(instance);
- visitNonCompositeChildren(instance, childInst => {
- if (!childInst._inDevTools) {
- // New DOM child component
- childInst._inDevTools = true;
- Reconciler.mountComponent(childInst);
- } else {
- // Updated DOM child component
- Reconciler.receiveComponent(childInst);
- }
- });
-
- // For any non-composite children that were removed by the latest render,
- // remove the corresponding ReactDOMComponent-like instances and notify
- // the devtools
- prevRenderedChildren.forEach(childInst => {
- if (!document.body.contains(childInst.node)) {
- instanceMap.delete(childInst.node);
- Reconciler.unmountComponent(childInst);
- }
- });
- };
-
- /** Notify devtools that a component has been unmounted from the DOM. */
- const componentRemoved = component => {
- const instance = updateReactComponent(component);
- visitNonCompositeChildren(childInst => {
- instanceMap.delete(childInst.node);
- Reconciler.unmountComponent(childInst);
- });
- Reconciler.unmountComponent(instance);
- instanceMap.delete(component);
- if (instance._rootID) {
- delete roots[instance._rootID];
- }
- };
-
- return {
- componentAdded,
- componentUpdated,
- componentRemoved,
-
- // Interfaces passed to devtools via __REACT_DEVTOOLS_GLOBAL_HOOK__.inject()
- ComponentTree,
- Mount,
- Reconciler
- };
-}
-
-/**
- * Return `true` if a preact component is a top level component rendered by
- * `render()` into a container Element.
- */
-function isRootComponent(component) {
- return !component.base.parentElement || !component.base.parentElement[ATTR_KEY];
-}
-
-/**
- * Visit all child instances of a ReactCompositeComponent-like object that are
- * not composite components (ie. they represent DOM elements or text)
- *
- * @param {Component} component
- * @param {(Component) => void} visitor
- */
-function visitNonCompositeChildren(component, visitor) {
- if (component._renderedComponent) {
- if (!component._renderedComponent._component) {
- visitor(component._renderedComponent);
- visitNonCompositeChildren(component._renderedComponent, visitor);
- }
- } else if (component._renderedChildren) {
- component._renderedChildren.forEach(child => {
- visitor(child);
- if (!child._component) visitNonCompositeChildren(child, visitor);
- });
- }
-}
-
-/**
- * Create a bridge between the preact component tree and React's dev tools
- * and register it.
- *
- * After this function is called, the React Dev Tools should be able to detect
- * "React" on the page and show the component tree.
- *
- * This function hooks into preact VNode creation in order to expose functional
- * components correctly, so it should be called before the root component(s)
- * are rendered.
- *
- * Returns a cleanup function which unregisters the hooks.
- */
-export function initDevTools() {
- if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
- // React DevTools are not installed
- return;
- }
-
- // Hook into preact element creation in order to wrap functional components
- // with stateful ones in order to make them visible in the devtools
- const nextVNode = options.vnode;
- options.vnode = (vnode) => {
- if (isFunctionalComponent(vnode)) wrapFunctionalComponent(vnode);
- if (nextVNode) return nextVNode(vnode);
- };
-
- // Notify devtools when preact components are mounted, updated or unmounted
- const bridge = createDevToolsBridge();
-
- const nextAfterMount = options.afterMount;
- options.afterMount = component => {
- bridge.componentAdded(component);
- if (nextAfterMount) nextAfterMount(component);
- };
-
- const nextAfterUpdate = options.afterUpdate;
- options.afterUpdate = component => {
- bridge.componentUpdated(component);
- if (nextAfterUpdate) nextAfterUpdate(component);
- };
-
- const nextBeforeUnmount = options.beforeUnmount;
- options.beforeUnmount = component => {
- bridge.componentRemoved(component);
- if (nextBeforeUnmount) nextBeforeUnmount(component);
- };
-
- // Notify devtools about this instance of "React"
- __REACT_DEVTOOLS_GLOBAL_HOOK__.inject(bridge);
-
- return () => {
- options.afterMount = nextAfterMount;
- options.afterUpdate = nextAfterUpdate;
- options.beforeUnmount = nextBeforeUnmount;
- };
-}