Skip to content
Permalink
Browse files

Added support for editable hook values (pending facebook/react/pull/1…

  • Loading branch information...
bvaughn committed Feb 20, 2019
1 parent 90f9837 commit 8cd8b29015646b65f7db7c1b39a0c9afa19612c9
@@ -225,6 +225,7 @@ type ReactCurrentDispatcher = {
};

type HooksNode = {
nativeHookIndex: number,
name: string,
value: mixed,
subHooks: Array<HooksNode>,
@@ -366,6 +367,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
const rootChildren = [];
let prevStack = null;
let levelChildren = rootChildren;
let nativeHookIndex = 0;
const stackOfChildren = [];
for (let i = 0; i < readHookLog.length; i++) {
const hook = readHookLog[i];
@@ -399,6 +401,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
levelChildren.push({
name: parseCustomHookName(stack[j - 1].functionName),
value: undefined,
nativeHookIndex: -1,
subHooks: children,
});
stackOfChildren.push(levelChildren);
@@ -409,12 +412,13 @@ function buildTree(rootStack, readHookLog): HooksTree {
levelChildren.push({
name: hook.primitive,
value: hook.value,
nativeHookIndex: hook.primitive === 'DebugValue' ? -1 : nativeHookIndex++,
subHooks: [],
});
}

// Associate custom hook values (useDebugValue() hook entries) with the correct hooks.
rollupDebugValues(rootChildren, null);
processDebugValues(rootChildren, null);

return rootChildren;
}
@@ -423,7 +427,7 @@ function buildTree(rootStack, readHookLog): HooksTree {
// That hook adds the user-provided values to the hooks tree.
// This method removes those values (so they don't appear in DevTools),
// and bubbles them up to the "value" attribute of their parent custom hook.
function rollupDebugValues(
function processDebugValues(
hooksTree: HooksTree,
parentHooksNode: HooksNode | null
): void {
@@ -436,7 +440,7 @@ function rollupDebugValues(
i--;
debugValueHooksNodes.push(hooksNode);
} else {
rollupDebugValues(hooksNode.subHooks, hooksNode);
processDebugValues(hooksNode.subHooks, hooksNode);
}
}

@@ -23,6 +23,14 @@ type InspectSelectParams = {|
rendererID: number,
|};

type OverrideHookParams = {|
id: number,
nativeHookIndex: number,
path: Array<string | number>,
rendererID: number,
value: any,
|};

type SetInParams = {|
id: number,
path: Array<string | number>,
@@ -40,6 +48,7 @@ export default class Agent extends EventEmitter {
bridge.addListener('highlightElementInDOM', this.highlightElementInDOM);
bridge.addListener('inspectElement', this.inspectElement);
bridge.addListener('overrideContext', this.overrideContext);
bridge.addListener('overrideHook', this.overrideHook);
bridge.addListener('overrideProps', this.overrideProps);
bridge.addListener('overrideState', this.overrideState);
bridge.addListener('selectElement', this.selectElement);
@@ -122,6 +131,21 @@ export default class Agent extends EventEmitter {
}
};

overrideHook = ({
id,
nativeHookIndex,
path,
rendererID,
value,
}: OverrideHookParams) => {
const renderer = this._rendererInterfaces[rendererID];
if (renderer == null) {
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
} else {
renderer.setInHook(id, nativeHookIndex, path, value);
}
};

overrideProps = ({ id, path, rendererID, value }: SetInParams) => {
const renderer = this._rendererInterfaces[rendererID];
if (renderer == null) {
@@ -1,11 +1,15 @@
// @flow

import type { Hook, ReactRenderer, RendererInterface } from './types';
import type { DevToolsHook, ReactRenderer, RendererInterface } from './types';
import Agent from './agent';

import { attach } from './renderer';

export function initBackend(hook: Hook, agent: Agent, global: Object): void {
export function initBackend(
hook: DevToolsHook,
agent: Agent,
global: Object
): void {
const subs = [
hook.sub(
'renderer-attached',
@@ -24,8 +24,8 @@ import { getUID } from '../utils';
import { inspectHooksOfFiber } from './ReactDebugHooks';

import type {
DevToolsHook,
Fiber,
Hook,
ReactRenderer,
FiberData,
RendererInterface,
@@ -151,7 +151,7 @@ function getInternalReactConstants(version) {
}

export function attach(
hook: Hook,
hook: DevToolsHook,
rendererID: number,
renderer: ReactRenderer,
global: Object
@@ -194,7 +194,7 @@ export function attach(
DEPRECATED_PLACEHOLDER_SYMBOL_STRING,
} = ReactSymbols;

const { overrideProps } = renderer;
const { overrideHook, overrideProps } = renderer;

const debug = (name: string, fiber: Fiber, parentFiber: ?Fiber): void => {
if (__DEBUG__) {
@@ -1141,7 +1141,10 @@ export function attach(
return {
id,

// Does the current renderer support editable props/state/hooks?
// Does the current renderer support editable hooks?
canEditHooks: typeof overrideHook === 'function',

// Does the current renderer support editable function props?
canEditFunctionProps: typeof overrideProps === 'function',

// Inspectable properties.
@@ -1163,6 +1166,20 @@ export function attach(
};
}

function setInHook(
id: number,
nativeHookIndex: number,
path: Array<string | number>,
value: any
) {
const fiber = findCurrentFiberUsingSlowPath(idToFiberMap.get(id));
if (fiber !== null) {
if (typeof overrideHook === 'function') {
overrideHook(fiber, nativeHookIndex, path, value);
}
}
}

function setInProps(id: number, path: Array<string | number>, value: any) {
const fiber = findCurrentFiberUsingSlowPath(idToFiberMap.get(id));
if (fiber !== null) {
@@ -1216,6 +1233,7 @@ export function attach(
cleanup,
renderer,
setInContext,
setInHook,
setInProps,
setInState,
walkTree,
@@ -33,6 +33,16 @@ export type ReactRenderer = {
findFiberByHostInstance: (hostInstance: NativeType) => ?Fiber,
version: string,
bundleType: BundleType,

// 16.9+
overrideHook?: ?(
fiber: Object,
nativeHookIndex: number,
path: Array<string | number>,
value: any
) => void,

// 16.7+
overrideProps?: ?(
fiber: Object,
path: Array<string | number>,
@@ -55,15 +65,21 @@ export type RendererInterface = {
inspectElement: (id: number) => InspectedElement | null,
renderer: ReactRenderer | null,
selectElement: (id: number) => void,
setInContext: (id: number, path: Array<string | number>, value: any) => void,
setInHook: (
id: number,
nativeHookIndex: number,
path: Array<string | number>,
value: any
) => void,
setInProps: (id: number, path: Array<string | number>, value: any) => void,
setInState: (id: number, path: Array<string | number>, value: any) => void,
setInContext: (id: number, path: Array<string | number>, value: any) => void,
walkTree: () => void,
};

export type Handler = (data: any) => void;

export type Hook = {
export type DevToolsHook = {
listeners: { [key: string]: Array<Handler> },
rendererInterfaces: Map<RendererID, RendererInterface>,
renderers: Map<RendererID, ReactRenderer>,
@@ -83,6 +99,7 @@ export type Hook = {
};

export type HooksNode = {
nativeHookIndex: number,
name: string,
value: mixed,
subHooks: Array<HooksNode>,
@@ -48,6 +48,9 @@ export type Owner = {|
export type InspectedElement = {|
id: number,

// Does the current renderer support editable hooks?
canEditHooks: boolean,

// Does the current renderer support editable function props?
canEditFunctionProps: boolean,

@@ -3,15 +3,22 @@
border-top: 1px solid var(--color-border);
}

.HooksNode {
.Hook {
padding-left: 0.75rem;
}

.NameValueRow {
display: flex;
}

.Name {
color: var(--color-attribute-name);
flex: 0 0 auto;
}
.Name:after {
content: ': ';
color: var(--color-text-color);
margin-right: 0.5rem;
}

.Value {

0 comments on commit 8cd8b29

Please sign in to comment.
You can’t perform that action at this time.