mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Refactor SearchInput component (used in Components tree) to be generic DevTools component with two uses: ComponentSearchInput and TimelineSearchInput. Refactored Timeline Suspense to more closely match other, newer Suspense patterns (e.g. inspect component, named hooks) and colocated Susepnse code in timelineCache file. Add search by component name functionality to the Timeline. For now, searching zooms in to the component measure and you can step through each time it rendered using the next/previous arrows.
103 lines
2.7 KiB
JavaScript
103 lines
2.7 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import * as React from 'react';
|
|
import {createContext, useMemo, useRef, useState} from 'react';
|
|
|
|
import type {
|
|
HorizontalScrollStateChangeCallback,
|
|
SearchRegExpStateChangeCallback,
|
|
ViewState,
|
|
} from './types';
|
|
import type {RefObject} from 'shared/ReactTypes';
|
|
|
|
export type Context = {|
|
|
file: File | null,
|
|
searchInputContainerRef: RefObject,
|
|
setFile: (file: File | null) => void,
|
|
viewState: ViewState,
|
|
|};
|
|
|
|
const TimelineContext = createContext<Context>(((null: any): Context));
|
|
TimelineContext.displayName = 'TimelineContext';
|
|
|
|
type Props = {|
|
|
children: React$Node,
|
|
|};
|
|
|
|
function TimelineContextController({children}: Props) {
|
|
const searchInputContainerRef = useRef(null);
|
|
const [file, setFile] = useState<string | null>(null);
|
|
|
|
// Recreate view state any time new profiling data is imported.
|
|
const viewState = useMemo<ViewState>(() => {
|
|
const horizontalScrollStateChangeCallbacks: Set<HorizontalScrollStateChangeCallback> = new Set();
|
|
const searchRegExpStateChangeCallbacks: Set<SearchRegExpStateChangeCallback> = new Set();
|
|
|
|
const horizontalScrollState = {
|
|
offset: 0,
|
|
length: 0,
|
|
};
|
|
|
|
const state: ViewState = {
|
|
horizontalScrollState,
|
|
onHorizontalScrollStateChange: callback => {
|
|
horizontalScrollStateChangeCallbacks.add(callback);
|
|
},
|
|
onSearchRegExpStateChange: callback => {
|
|
searchRegExpStateChangeCallbacks.add(callback);
|
|
},
|
|
searchRegExp: null,
|
|
updateHorizontalScrollState: scrollState => {
|
|
if (
|
|
horizontalScrollState.offset === scrollState.offset &&
|
|
horizontalScrollState.length === scrollState.length
|
|
) {
|
|
return;
|
|
}
|
|
|
|
horizontalScrollState.offset = scrollState.offset;
|
|
horizontalScrollState.length = scrollState.length;
|
|
|
|
horizontalScrollStateChangeCallbacks.forEach(callback => {
|
|
callback(scrollState);
|
|
});
|
|
},
|
|
updateSearchRegExpState: (searchRegExp: RegExp | null) => {
|
|
state.searchRegExp = searchRegExp;
|
|
|
|
searchRegExpStateChangeCallbacks.forEach(callback => {
|
|
callback(searchRegExp);
|
|
});
|
|
},
|
|
viewToMutableViewStateMap: new Map(),
|
|
};
|
|
|
|
return state;
|
|
}, [file]);
|
|
|
|
const value = useMemo(
|
|
() => ({
|
|
file,
|
|
searchInputContainerRef,
|
|
setFile,
|
|
viewState,
|
|
}),
|
|
[file, setFile, viewState],
|
|
);
|
|
|
|
return (
|
|
<TimelineContext.Provider value={value}>
|
|
{children}
|
|
</TimelineContext.Provider>
|
|
);
|
|
}
|
|
|
|
export {TimelineContext, TimelineContextController};
|