[DevTools] Make a non-editable name of KeyValue clickable (#34095)
This has been bothering me. You can click the arrow and the value to expand/collapse a KeyValue row but not the name. When the name is not editable it should be clickable. Such as when inspecting a Promise value.
Sebastian Markbåge committed
Aug 4, 2025 at 09:27 UTC
8e3db095aa99ffdf8ae2bc3944d1dffcebefbbee
1 file changed
+32
-19
packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js
+32
-19
@@ -210,6 +210,13 @@ export default function KeyValue({
210
canRenameTheCurrentPath = canRenamePathsAtDepth(depth);
211
}
212
213
+ const hasChildren =
214
+ typeof value === 'object' &&
215
+ value !== null &&
216
+ (canEditValues ||
217
+ (isArray(value) && value.length > 0) ||
218
+ Object.entries(value).length > 0);
219
+
220
let renderedName;
221
if (isDirectChildOfAnArray) {
222
if (canDeletePaths) {
@@ -218,27 +225,37 @@ export default function KeyValue({
225
);
226
} else {
227
renderedName = (
221
- <span className={styles.Name}>
228
+ <span
229
+ className={styles.Name}
230
+ onClick={isInspectable || hasChildren ? toggleIsOpen : null}>
231
{name}
232
{!!hookName && <span className={styles.HookName}>({hookName})</span>}
233
+ <span className={styles.AfterName}>:</span>
234
</span>
235
);
236
}
237
} else if (canRenameTheCurrentPath) {
238
renderedName = (
229
- <EditableName
230
- allowEmpty={canDeletePaths}
231
- className={styles.EditableName}
232
- initialValue={name}
233
- overrideName={renamePath}
234
- path={path}
235
- />
239
+ <>
240
+ <EditableName
241
+ allowEmpty={canDeletePaths}
242
+ className={styles.EditableName}
243
+ initialValue={name}
244
+ overrideName={renamePath}
245
+ path={path}
246
+ />
247
+ <span className={styles.AfterName}>:</span>
248
+ </>
249
);
250
} else {
251
renderedName = (
239
- <span className={styles.Name} data-testname="NonEditableName">
252
+ <span
253
+ className={styles.Name}
254
+ data-testname="NonEditableName"
255
+ onClick={isInspectable || hasChildren ? toggleIsOpen : null}>
256
{name}
257
{!!hookName && <span className={styles.HookName}>({hookName})</span>}
258
+ <span className={styles.AfterName}>:</span>
259
</span>
260
);
261
}
@@ -286,7 +303,6 @@ export default function KeyValue({
303
style={style}>
304
<div className={styles.ExpandCollapseToggleSpacer} />
305
{renderedName}
289
- <div className={styles.AfterName}>:</div>
306
{canEditValues ? (
307
<EditableValue
308
overrideValue={overrideValue}
@@ -328,7 +344,6 @@ export default function KeyValue({
344
style={style}>
345
<div className={styles.ExpandCollapseToggleSpacer} />
346
{renderedName}
331
- <div className={styles.AfterName}>:</div>
347
<span
348
className={styles.Link}
349
onClick={() => {
@@ -365,7 +380,6 @@ export default function KeyValue({
380
<div className={styles.ExpandCollapseToggleSpacer} />
381
)}
382
{renderedName}
368
- <div className={styles.AfterName}>:</div>
383
<span
384
className={styles.Value}
385
onClick={isInspectable ? toggleIsOpen : undefined}>
@@ -388,7 +402,6 @@ export default function KeyValue({
402
}
403
} else {
404
if (isArray(value)) {
391
- const hasChildren = value.length > 0 || canEditValues;
405
const displayName = getMetaValueLabel(value);
406
407
children = value.map((innerValue, index) => (
@@ -449,12 +462,11 @@ export default function KeyValue({
462
ref={contextMenuTriggerRef}
463
style={style}>
464
{hasChildren ? (
452
- <ExpandCollapseToggle isOpen={isOpen} setIsOpen={setIsOpen} />
465
+ <ExpandCollapseToggle isOpen={isOpen} setIsOpen={toggleIsOpen} />
466
) : (
467
<div className={styles.ExpandCollapseToggleSpacer} />
468
)}
469
{renderedName}
457
- <div className={styles.AfterName}>:</div>
470
<span
471
className={styles.Value}
472
onClick={hasChildren ? toggleIsOpen : undefined}>
@@ -472,7 +484,6 @@ export default function KeyValue({
484
entries.sort(alphaSortEntries);
485
}
486
475
- const hasChildren = entries.length > 0 || canEditValues;
487
const displayName = getMetaValueLabel(value);
488
489
children = entries.map(([key, keyValue]): ReactElement<any> => (
@@ -531,12 +542,11 @@ export default function KeyValue({
542
ref={contextMenuTriggerRef}
543
style={style}>
544
{hasChildren ? (
534
- <ExpandCollapseToggle isOpen={isOpen} setIsOpen={setIsOpen} />
545
+ <ExpandCollapseToggle isOpen={isOpen} setIsOpen={toggleIsOpen} />
546
) : (
547
<div className={styles.ExpandCollapseToggleSpacer} />
548
)}
549
{renderedName}
539
- <div className={styles.AfterName}>:</div>
550
<span
551
className={styles.Value}
552
onClick={hasChildren ? toggleIsOpen : undefined}>
@@ -567,7 +577,10 @@ function DeleteToggle({deletePath, name, path}) {
577
title="Delete entry">
578
<ButtonIcon type="delete" />
579
</Button>
570
- <span className={styles.Name}>{name}</span>
580
+ <span className={styles.Name}>
581
+ {name}
582
+ <span className={styles.AfterName}>:</span>
583
+ </span>
584
</>
585
);
586
}