Move highlighter to flipper-plugin
Summary: This stack moves the DataInspector component to flipper-plugin. The first diffs will move some utility abstractions to turn this into smaller steps Reviewed By: passy Differential Revision: D27591890 fbshipit-source-id: d0285ca31b6c9b334000dd15c722b9bda7638d73
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cd27e4c010
commit
b6674bf96b
@@ -103,7 +103,7 @@ export {
|
||||
default as DataDescription,
|
||||
DataDescriptionType,
|
||||
} from './ui/components/data-inspector/DataDescription';
|
||||
export {HighlightManager} from './ui/components/Highlight';
|
||||
export {_HighlightManager as HighlightManager} from 'flipper-plugin';
|
||||
export {default as Tabs} from './ui/components/Tabs';
|
||||
export {default as Tab} from './ui/components/Tab';
|
||||
export {default as Input} from './ui/components/Input';
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import {colors} from './colors';
|
||||
import React, {
|
||||
useEffect,
|
||||
memo,
|
||||
useState,
|
||||
useRef,
|
||||
useMemo,
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'react';
|
||||
import {debounce} from 'lodash';
|
||||
|
||||
const Highlighted = styled.span({
|
||||
backgroundColor: colors.lemon,
|
||||
});
|
||||
|
||||
export interface HighlightManager {
|
||||
setFilter(text: string | undefined): void;
|
||||
render(text: string): React.ReactNode;
|
||||
}
|
||||
|
||||
function createHighlightManager(initialText: string = ''): HighlightManager {
|
||||
const callbacks = new Set<(prev: string, next: string) => void>();
|
||||
let matches = 0;
|
||||
let currentFilter = initialText;
|
||||
|
||||
const Highlight: React.FC<{text: string}> = memo(({text}) => {
|
||||
const [, setUpdate] = useState(0);
|
||||
const elem = useRef<HTMLSpanElement | null>(null);
|
||||
useEffect(() => {
|
||||
function onChange(prevHighlight: string, newHighlight: string) {
|
||||
const prevIndex = text.toLowerCase().indexOf(prevHighlight);
|
||||
const newIndex = text.toLowerCase().indexOf(newHighlight);
|
||||
if (prevIndex !== newIndex || newIndex !== -1) {
|
||||
// either we had a result, and we have no longer,
|
||||
// or we still have a result, but the highlightable text changed
|
||||
if (newIndex !== -1) {
|
||||
if (++matches === 1) {
|
||||
elem.current?.parentElement?.parentElement?.scrollIntoView?.();
|
||||
}
|
||||
}
|
||||
setUpdate((s) => s + 1);
|
||||
}
|
||||
}
|
||||
callbacks.add(onChange);
|
||||
return () => {
|
||||
callbacks.delete(onChange);
|
||||
};
|
||||
}, [text]);
|
||||
|
||||
const index = text.toLowerCase().indexOf(currentFilter);
|
||||
return (
|
||||
<span ref={elem}>
|
||||
{index === -1 ? (
|
||||
text
|
||||
) : (
|
||||
<>
|
||||
{text.substr(0, index)}
|
||||
<Highlighted>
|
||||
{text.substr(index, currentFilter.length)}
|
||||
</Highlighted>
|
||||
{text.substr(index + currentFilter.length)}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
setFilter: debounce((text: string = '') => {
|
||||
if (currentFilter !== text) {
|
||||
matches = 0;
|
||||
const base = currentFilter;
|
||||
currentFilter = text.toLowerCase();
|
||||
callbacks.forEach((cb) => cb(base, currentFilter));
|
||||
}
|
||||
}, 100),
|
||||
render(text: string) {
|
||||
return <Highlight text={text} />;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const HighlightContext = createContext<HighlightManager>({
|
||||
setFilter(_text: string) {
|
||||
throw new Error('Cannot set the filter of a stub highlight manager');
|
||||
},
|
||||
render(text: string) {
|
||||
// stub implementation in case we render a component without a Highlight context
|
||||
return text;
|
||||
},
|
||||
});
|
||||
|
||||
export function HighlightProvider({
|
||||
text,
|
||||
children,
|
||||
}: {
|
||||
text: string | undefined;
|
||||
children: React.ReactElement;
|
||||
}) {
|
||||
const highlightManager = useMemo(() => createHighlightManager(text), []);
|
||||
|
||||
useEffect(() => {
|
||||
highlightManager.setFilter(text);
|
||||
}, [text]);
|
||||
|
||||
return (
|
||||
<HighlightContext.Provider value={highlightManager}>
|
||||
{children}
|
||||
</HighlightContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useHighlighter(): HighlightManager {
|
||||
return useContext(HighlightContext);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import {colors} from '../colors';
|
||||
import Input from '../Input';
|
||||
import React, {KeyboardEvent} from 'react';
|
||||
import Glyph from '../Glyph';
|
||||
import {HighlightContext} from '../Highlight';
|
||||
import {_HighlightContext} from 'flipper-plugin';
|
||||
import Select from '../Select';
|
||||
import TimelineDataDescription from './TimelineDataDescription';
|
||||
|
||||
@@ -575,8 +575,8 @@ class DataDescriptionContainer extends PureComponent<{
|
||||
editable: boolean;
|
||||
commit: (opts: DescriptionCommitOptions) => void;
|
||||
}> {
|
||||
static contextType = HighlightContext; // Replace with useHighlighter
|
||||
context!: React.ContextType<typeof HighlightContext>;
|
||||
static contextType = _HighlightContext; // Replace with useHighlighter
|
||||
context!: React.ContextType<typeof _HighlightContext>;
|
||||
|
||||
onChangeCheckbox = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.commit({
|
||||
|
||||
@@ -21,7 +21,10 @@ import {colors} from '../colors';
|
||||
import {clipboard} from 'electron';
|
||||
import React from 'react';
|
||||
import {TooltipOptions} from '../TooltipProvider';
|
||||
import {useHighlighter, HighlightManager} from '../Highlight';
|
||||
import {
|
||||
_useHighlighter as useHighlighter,
|
||||
_HighlightManager,
|
||||
} from 'flipper-plugin';
|
||||
|
||||
export {DataValueExtractor} from './DataPreview';
|
||||
|
||||
@@ -142,7 +145,7 @@ type DataInspectorProps = {
|
||||
onRenderName?: (
|
||||
path: Array<string>,
|
||||
name: string,
|
||||
highlighter: HighlightManager,
|
||||
highlighter: _HighlightManager,
|
||||
) => React.ReactElement;
|
||||
/**
|
||||
* Render callback that can be used to customize the rendering of object values.
|
||||
|
||||
@@ -12,7 +12,7 @@ import {PureComponent} from 'react';
|
||||
import DataInspector from './DataInspector';
|
||||
import React from 'react';
|
||||
import {DataValueExtractor} from './DataPreview';
|
||||
import {HighlightProvider, HighlightManager} from '../Highlight';
|
||||
import {_HighlightProvider, _HighlightManager} from 'flipper-plugin';
|
||||
|
||||
export type ManagedDataInspectorProps = {
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ export type ManagedDataInspectorProps = {
|
||||
onRenderName?: (
|
||||
path: Array<string>,
|
||||
name: string,
|
||||
highlighter: HighlightManager,
|
||||
highlighter: _HighlightManager,
|
||||
) => React.ReactElement;
|
||||
/**
|
||||
* Render callback that can be used to customize the rendering of object values.
|
||||
@@ -173,7 +173,7 @@ export default class ManagedDataInspector extends PureComponent<
|
||||
|
||||
render() {
|
||||
return (
|
||||
<HighlightProvider text={this.props.filter}>
|
||||
<_HighlightProvider text={this.props.filter}>
|
||||
<DataInspector
|
||||
data={this.props.data}
|
||||
diff={this.props.diff}
|
||||
@@ -191,7 +191,7 @@ export default class ManagedDataInspector extends PureComponent<
|
||||
depth={0}
|
||||
parentAncestry={EMPTY_ARRAY}
|
||||
/>
|
||||
</HighlightProvider>
|
||||
</_HighlightProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ test('can filter for data', async () => {
|
||||
<span>
|
||||
"j
|
||||
<span
|
||||
class="css-i709sw-Highlighted ep1h60f0"
|
||||
class="css-zr1u3c-Highlighted eiud9hg0"
|
||||
>
|
||||
son
|
||||
</span>
|
||||
|
||||
@@ -180,4 +180,3 @@ export {default as AlternatingRows} from './components/AlternatingRows';
|
||||
export {Layout} from 'flipper-plugin';
|
||||
|
||||
export {default as Scrollable} from './components/Scrollable';
|
||||
export * from './components/Highlight';
|
||||
|
||||
Reference in New Issue
Block a user