diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index 09f811172f3..a73acd55bf4 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -582,6 +582,7 @@ describe('InspectedElement', () => { boolean_false={false} boolean_true={true} infinity={Infinity} + minus_infinity={-Infinity} integer_zero={0} integer_one={1} float={1.23} @@ -604,6 +605,7 @@ describe('InspectedElement', () => { "infinity": Infinity, "integer_one": 1, "integer_zero": 0, + "minus_infinity": -Infinity, "nan": NaN, "string": "abc", "string_empty": "", diff --git a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js index f306ab97093..62ba2e13608 100644 --- a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js @@ -98,6 +98,7 @@ describe('InspectedElementContext', () => { boolean_false: false, boolean_true: true, infinity: Infinity, + minus_infinity: -Infinity, integer_zero: 0, integer_one: 1, float: 1.23, @@ -128,6 +129,7 @@ describe('InspectedElementContext', () => { "infinity": Infinity, "integer_one": 1, "integer_zero": 0, + "minus_infinity": -Infinity, "nan": NaN, "string": "abc", "string_empty": "", diff --git a/packages/react-devtools-shared/src/devtools/utils.js b/packages/react-devtools-shared/src/devtools/utils.js index 876e01345b4..43d3ea6c837 100644 --- a/packages/react-devtools-shared/src/devtools/utils.js +++ b/packages/react-devtools-shared/src/devtools/utils.js @@ -235,6 +235,8 @@ export function smartParse(value: any): any | void | number { switch (value) { case 'Infinity': return Infinity; + case '-Infinity': + return -Infinity; case 'NaN': return NaN; case 'undefined': @@ -249,7 +251,7 @@ export function smartStringify(value: any): string { if (Number.isNaN(value)) { return 'NaN'; } else if (!Number.isFinite(value)) { - return 'Infinity'; + return value > 0 ? 'Infinity' : '-Infinity'; } } else if (value === undefined) { return 'undefined'; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js index 5623d507a3b..502056f936c 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js @@ -384,6 +384,23 @@ export default function Tree(): React.Node { const handleMouseLeave = clearHighlightHostInstance; + // The synthetic onMouseLeave on the tree div only fires within the document, + // so we need a native listener on the document itself. + useEffect(() => { + const container = focusTargetRef.current; + if (container == null) { + return; + } + const ownerDocument = container.ownerDocument; + ownerDocument.addEventListener('mouseleave', clearHighlightHostInstance); + return () => { + ownerDocument.removeEventListener( + 'mouseleave', + clearHighlightHostInstance, + ); + }; + }, [clearHighlightHostInstance]); + // Let react-window know to re-render any time the underlying tree data changes. // This includes the owner context, since it controls a filtered view of the tree. const itemData = useMemo( diff --git a/packages/react-devtools-shared/src/hydration.js b/packages/react-devtools-shared/src/hydration.js index 2468917d939..3670514ff4c 100644 --- a/packages/react-devtools-shared/src/hydration.js +++ b/packages/react-devtools-shared/src/hydration.js @@ -596,6 +596,7 @@ export function dehydrate( return value; } case 'infinity': + case '-infinity': case 'nan': case 'undefined': // Some values are lossy when sent through a WebSocket. @@ -704,6 +705,8 @@ export function hydrate( return; } else if (value.type === 'infinity') { parent[last] = Infinity; + } else if (value.type === '-infinity') { + parent[last] = -Infinity; } else if (value.type === 'nan') { parent[last] = NaN; } else if (value.type === 'undefined') { diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 66de8440b65..aa7ba33dc59 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -708,6 +708,7 @@ export type DataType = | 'html_all_collection' | 'html_element' | 'infinity' + | '-infinity' | 'iterator' | 'opaque_iterator' | 'nan' @@ -765,7 +766,7 @@ export function getDataType(data: Object): DataType { if (Number.isNaN(data)) { return 'nan'; } else if (!Number.isFinite(data)) { - return 'infinity'; + return data > 0 ? 'infinity' : '-infinity'; } else { return 'number'; } @@ -1219,6 +1220,7 @@ export function formatDataForPreview( case 'boolean': case 'number': case 'infinity': + case '-infinity': case 'nan': case 'null': case 'undefined': diff --git a/packages/react-devtools-shell/src/app/InspectableElements/SimpleValues.js b/packages/react-devtools-shell/src/app/InspectableElements/SimpleValues.js index 22c54ec91ee..1a17dc2279c 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/SimpleValues.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/SimpleValues.js @@ -25,6 +25,7 @@ export default class SimpleValues extends Component { null={null} nan={NaN} infinity={Infinity} + minusInfinity={-Infinity} true={true} false={false} function={noop}