diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.css b/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.css
index c708adcffdbc33..040d2e4d28933a 100644
--- a/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.css
+++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.css
@@ -28,3 +28,19 @@
justify-content: center;
color: var(--color-dim);
}
+
+.Input {
+ background: none;
+ font-size: var(--font-size-sans-normal);
+ text-align: right;
+ font-family: var(--font-family-monospace);
+ border: 1px solid transparent;
+ border-radius: 0.125rem;
+ padding: 0.125rem;
+ color: var(--color-attribute-editable-value);
+}
+
+.Input:focus {
+ background-color: var(--color-button-background-focus);
+ outline: none;
+}
diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js b/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js
index b79569df1e48f4..42510f08761a73 100644
--- a/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js
+++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js
@@ -8,7 +8,7 @@
*/
import * as React from 'react';
-import {Fragment, useCallback, useContext, useMemo} from 'react';
+import {Fragment, useContext, useMemo} from 'react';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import {ProfilerContext} from './ProfilerContext';
@@ -86,47 +86,89 @@ export default function SnapshotSelector(_: Props) {
let label = null;
if (numFilteredCommits > 0) {
- label =
- `${selectedFilteredCommitIndex + 1}`.padStart(
- `${numFilteredCommits}`.length,
- '0',
- ) +
- ' / ' +
- numFilteredCommits;
+ const handleCommitInputChange = event => {
+ const value = parseInt(event.currentTarget.value, 10);
+ if (!isNaN(value)) {
+ const filteredIndex = Math.min(
+ Math.max(value - 1, 0),
+
+ // Snashots are shown to the user as 1-based
+ // but the indices within the profiler data array ar 0-based.
+ numFilteredCommits - 1,
+ );
+ selectCommitIndex(filteredCommitIndices[filteredIndex]);
+ }
+ };
+
+ const handleClick = event => {
+ event.currentTarget.select();
+ };
+
+ const handleKeyDown = event => {
+ switch (event.key) {
+ case 'ArrowDown':
+ viewPrevCommit();
+ event.stopPropagation();
+ break;
+ case 'ArrowUp':
+ viewNextCommit();
+ event.stopPropagation();
+ break;
+ default:
+ break;
+ }
+ };
+
+ const input = (
+
+ );
+
+ label = (
+
+ {input} / {numFilteredCommits}
+
+ );
}
- const viewNextCommit = useCallback(() => {
+ const viewNextCommit = () => {
let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) + 1;
if (nextCommitIndex === filteredCommitIndices.length) {
nextCommitIndex = 0;
}
selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
- }, [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex]);
- const viewPrevCommit = useCallback(() => {
+ };
+ const viewPrevCommit = () => {
let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) - 1;
if (nextCommitIndex < 0) {
nextCommitIndex = filteredCommitIndices.length - 1;
}
selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
- }, [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex]);
+ };
- const handleKeyDown = useCallback(
- event => {
- switch (event.key) {
- case 'ArrowLeft':
- viewPrevCommit();
- event.stopPropagation();
- break;
- case 'ArrowRight':
- viewNextCommit();
- event.stopPropagation();
- break;
- default:
- break;
- }
- },
- [viewNextCommit, viewPrevCommit],
- );
+ const handleKeyDown = event => {
+ switch (event.key) {
+ case 'ArrowLeft':
+ viewPrevCommit();
+ event.stopPropagation();
+ break;
+ case 'ArrowRight':
+ viewNextCommit();
+ event.stopPropagation();
+ break;
+ default:
+ break;
+ }
+ };
if (commitData.length === 0) {
return null;