Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ export default class Store extends EventEmitter<{
// Only used in browser extension for synchronization with built-in Elements panel.
_lastSelectedHostInstanceElementId: Element['id'] | null = null;

// Maximum recorded node depth during the lifetime of this Store.
// Can only increase: not guaranteed to return maximal value for currently recorded elements.
_maximumRecordedDepth = 0;

constructor(bridge: FrontendBridge, config?: Config) {
super();

Expand Down Expand Up @@ -698,6 +702,50 @@ export default class Store extends EventEmitter<{
return index;
}

isDescendantOf(parentId: number, descendantId: number): boolean {
if (descendantId === 0) {
return false;
}

const descendant = this.getElementByID(descendantId);
if (descendant === null) {
return false;
}

if (descendant.parentID === parentId) {
return true;
}

const parent = this.getElementByID(parentId);
if (!parent || parent.depth >= descendant.depth) {
return false;
}

return this.isDescendantOf(parentId, descendant.parentID);
}

/**
* Returns index of the lowest descendant element, if available.
* May not be the deepest element, the lowest is used in a sense of bottom-most from UI Tree representation perspective.
*/
getIndexOfLowestDescendantElement(element: Element): number | null {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe clarify somehow this is not the "lowest" as in "deepest" but the bottom-most branch (if I understood it correctly)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, lowest in a sense of the bottom-most "branch", if you look at it from UI perspective. I do agree that "deepest" is probably not the right word here.

let current: null | Element = element;
while (current !== null) {
if (current.isCollapsed || current.children.length === 0) {
if (current === element) {
return null;
}

return this.getIndexOfElementID(current.id);
} else {
const lastChildID = current.children[current.children.length - 1];
current = this.getElementByID(lastChildID);
}
}

return null;
}

getOwnersListForElement(ownerID: number): Array<Element> {
const list: Array<Element> = [];
const element = this._idToElement.get(ownerID);
Expand Down Expand Up @@ -1089,9 +1137,15 @@ export default class Store extends EventEmitter<{
compiledWithForget,
} = parseElementDisplayNameFromBackend(displayName, type);

const elementDepth = parentElement.depth + 1;
this._maximumRecordedDepth = Math.max(
this._maximumRecordedDepth,
elementDepth,
);

const element: Element = {
children: [],
depth: parentElement.depth + 1,
depth: elementDepth,
displayName: displayNameWithoutHOCs,
hocDisplayNames,
id,
Expand Down Expand Up @@ -1536,6 +1590,14 @@ export default class Store extends EventEmitter<{
}
};

/**
* Maximum recorded node depth during the lifetime of this Store.
* Can only increase: not guaranteed to return maximal value for currently recorded elements.
*/
getMaximumRecordedDepth(): number {
return this._maximumRecordedDepth;
}

updateHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
this._hookSettings = settings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function Components(_: {}) {

const LOCAL_STORAGE_KEY = 'React::DevTools::createResizeReducer';
const VERTICAL_MODE_MAX_WIDTH = 600;
const MINIMUM_SIZE = 50;
const MINIMUM_SIZE = 100;

function initResizeState(): ResizeState {
let horizontalPercentage = 0.65;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.Element,
.HoveredElement,
.InactiveSelectedElement,
.SelectedElement,
.HoveredElement {
.HighlightedElement,
.InactiveHighlightedElement,
.SelectedElement {
color: var(--color-component-name);
}
.HoveredElement {
Expand All @@ -10,8 +12,15 @@
.InactiveSelectedElement {
background-color: var(--color-background-inactive);
}
.HighlightedElement {
background-color: var(--color-selected-tree-highlight-active);
}
.InactiveHighlightedElement {
background-color: var(--color-selected-tree-highlight-inactive);
}

.Wrapper {
position: relative;
padding: 0 0.25rem;
white-space: pre;
height: var(--line-height-data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ export default function Element({data, index, style}: Props): React.Node {

const [isHovered, setIsHovered] = useState(false);

const {isNavigatingWithKeyboard, onElementMouseEnter, treeFocused} = data;
const id = element === null ? null : element.id;
const isSelected = inspectedElementID === id;

const errorsAndWarningsSubscription = useMemo(
() => ({
getCurrentValue: () =>
Expand All @@ -68,6 +64,15 @@ export default function Element({data, index, style}: Props): React.Node {
}>(errorsAndWarningsSubscription);

const changeOwnerAction = useChangeOwnerAction();

// Handle elements that are removed from the tree while an async render is in progress.
if (element == null) {
console.warn(`<Element> Could not find element at index ${index}`);

// This return needs to happen after hooks, since hooks can't be conditional.
return null;
}

const handleDoubleClick = () => {
if (id !== null) {
changeOwnerAction(id);
Expand Down Expand Up @@ -107,22 +112,28 @@ export default function Element({data, index, style}: Props): React.Node {
event.preventDefault();
};

// Handle elements that are removed from the tree while an async render is in progress.
if (element == null) {
console.warn(`<Element> Could not find element at index ${index}`);

// This return needs to happen after hooks, since hooks can't be conditional.
return null;
}

const {
id,
depth,
displayName,
hocDisplayNames,
isStrictModeNonCompliant,
key,
compiledWithForget,
} = element;
const {
isNavigatingWithKeyboard,
onElementMouseEnter,
treeFocused,
calculateElementOffset,
} = data;

const isSelected = inspectedElementID === id;
const isDescendantOfSelected =
inspectedElementID !== null &&
!isSelected &&
store.isDescendantOf(inspectedElementID, id);
const elementOffset = calculateElementOffset(depth);

// Only show strict mode non-compliance badges for top level elements.
// Showing an inline badge for every element in the tree would be noisy.
Expand All @@ -135,6 +146,10 @@ export default function Element({data, index, style}: Props): React.Node {
: styles.InactiveSelectedElement;
} else if (isHovered && !isNavigatingWithKeyboard) {
className = styles.HoveredElement;
} else if (isDescendantOfSelected) {
className = treeFocused
? styles.HighlightedElement
: styles.InactiveHighlightedElement;
}

return (
Expand All @@ -144,17 +159,13 @@ export default function Element({data, index, style}: Props): React.Node {
onMouseLeave={handleMouseLeave}
onMouseDown={handleClick}
onDoubleClick={handleDoubleClick}
style={style}
data-testname="ComponentTreeListItem"
data-depth={depth}>
style={{
...style,
paddingLeft: elementOffset,
}}
data-testname="ComponentTreeListItem">
{/* This wrapper is used by Tree for measurement purposes. */}
<div
className={styles.Wrapper}
style={{
// Left offset presents the appearance of a nested tree structure.
// We must use padding rather than margin/left because of the selected background color.
transform: `translateX(calc(${depth} * var(--indentation-size)))`,
}}>
<div className={styles.Wrapper}>
{ownerID === null && (
<ExpandCollapseToggle element={element} store={store} />
)}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
display: flex;
flex-direction: column;
border-top: 1px solid var(--color-border);

/* Default size will be adjusted by Tree after scrolling */
--indentation-size: 12px;
}

.List {
overflow-x: hidden !important;
.InnerElementType {
position: relative;
}

.InnerElementType {
overflow-x: hidden;
.VerticalDelimiter {
position: absolute;
width: 0.025rem;
background: #b0b0b0;
}

.SearchInput {
Expand Down Expand Up @@ -97,4 +96,4 @@

.Link {
color: var(--color-button-active);
}
}
Loading
Loading