main
js 63 lines 1.55 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11
12 import {createRegExp} from '../utils';
13
14 import {TreeStateContext} from './TreeContext';
15 import styles from './Element.css';
16
17 const {useMemo, useContext} = React;
18
19 type Props = {
20 displayName: string | null,
21 id: number,
22 };
23
24 function IndexableDisplayName({displayName, id}: Props): React.Node {
25 const {searchIndex, searchResults, searchText} = useContext(TreeStateContext);
26 const isSearchResult = useMemo(() => {
27 return searchResults.includes(id);
28 }, [id, searchResults]);
29 const isCurrentResult =
30 searchIndex !== null && id === searchResults[searchIndex];
31
32 if (!isSearchResult || displayName === null) {
33 return displayName;
34 }
35
36 const match = createRegExp(searchText).exec(displayName);
37
38 if (match === null) {
39 return displayName;
40 }
41
42 const startIndex = match.index;
43 const stopIndex = startIndex + match[0].length;
44
45 const children = [];
46 if (startIndex > 0) {
47 children.push(<span key="begin">{displayName.slice(0, startIndex)}</span>);
48 }
49 children.push(
50 <mark
51 key="middle"
52 className={isCurrentResult ? styles.CurrentHighlight : styles.Highlight}>
53 {displayName.slice(startIndex, stopIndex)}
54 </mark>,
55 );
56 if (stopIndex < displayName.length) {
57 children.push(<span key="end">{displayName.slice(stopIndex)}</span>);
58 }
59
60 return children;
61 }
62
63 export default IndexableDisplayName;