/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitList.js
302 строки
9 KB
Jan Kassens
[flow] upgrade to 0.225.1 (#27871)
02 янв 2024, 22:39
Не верифицирован
02 янв 2024, 22:39
45d61cf
Код
Авторство
О чём код?
/** * Copyright (c) Meta Platforms, Inc. and 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 type {CommitDataFrontend} from './types'; import * as React from 'react'; import {useEffect, useMemo, useRef, useState} from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; import {FixedSizeList} from 'react-window'; import SnapshotCommitListItem from './SnapshotCommitListItem'; import {minBarWidth} from './constants'; import {formatDuration, formatTime} from './utils'; import Tooltip from './Tooltip'; import styles from './SnapshotCommitList.css'; export type ItemData = { commitTimes: Array<number>, filteredCommitIndices: Array<number>, maxDuration: number, selectedCommitIndex: number | null, selectedFilteredCommitIndex: number | null, selectCommitIndex: (index: number) => void, setHoveredCommitIndex: (index: number) => void, startCommitDrag: (newDragState: DragState) => void, totalDurations: Array<number>, }; type Props = { commitData: $ReadOnlyArray<CommitDataFrontend>, commitTimes: Array<number>, filteredCommitIndices: Array<number>, selectedCommitIndex: number | null, selectedFilteredCommitIndex: number | null, selectCommitIndex: (index: number) => void, totalDurations: Array<number>, }; export default function SnapshotCommitList({ commitData, commitTimes, filteredCommitIndices, selectedCommitIndex, selectedFilteredCommitIndex, selectCommitIndex, totalDurations, }: Props): React.Node { return ( <AutoSizer> {({height, width}) => ( <List commitData={commitData} commitTimes={commitTimes} height={height} filteredCommitIndices={filteredCommitIndices} selectedCommitIndex={selectedCommitIndex} selectedFilteredCommitIndex={selectedFilteredCommitIndex} selectCommitIndex={selectCommitIndex} totalDurations={totalDurations} width={width} /> )} </AutoSizer> ); } type ListProps = { commitData: $ReadOnlyArray<CommitDataFrontend>, commitTimes: Array<number>, height: number, filteredCommitIndices: Array<number>, selectedCommitIndex: number | null, selectedFilteredCommitIndex: number | null, selectCommitIndex: (index: number) => void, totalDurations: Array<number>, width: number, }; type DragState = { commitIndex: number, left: number, sizeIncrement: number, }; function List({ commitData, selectedCommitIndex, commitTimes, height, filteredCommitIndices, selectedFilteredCommitIndex, selectCommitIndex, totalDurations, width, }: ListProps) { // $FlowFixMe[incompatible-use] const listRef = useRef<FixedSizeList<ItemData> | null>(null); const divRef = useRef<HTMLDivElement | null>(null); const prevCommitIndexRef = useRef<number | null>(null); // Make sure a newly selected snapshot is fully visible within the list. useEffect(() => { if (selectedFilteredCommitIndex !== prevCommitIndexRef.current) { prevCommitIndexRef.current = selectedFilteredCommitIndex; if (selectedFilteredCommitIndex !== null && listRef.current !== null) { listRef.current.scrollToItem(selectedFilteredCommitIndex); } } }, [listRef, selectedFilteredCommitIndex]); const itemSize = useMemo( () => Math.max(minBarWidth, width / filteredCommitIndices.length), [filteredCommitIndices, width], ); const maxDuration = useMemo( () => totalDurations.reduce((max, duration) => Math.max(max, duration), 0), [totalDurations], ); const maxCommitIndex = filteredCommitIndices.length - 1; const [dragState, setDragState] = useState<DragState | null>(null); const handleDragCommit = ({buttons, pageX}: any) => { if (buttons === 0) { setDragState(null); return; } if (dragState !== null) { const {commitIndex, left, sizeIncrement} = dragState; let newCommitIndex = commitIndex; let newCommitLeft = left; if (pageX < newCommitLeft) { while (pageX < newCommitLeft) { newCommitLeft -= sizeIncrement; newCommitIndex -= 1; } } else { let newCommitRectRight = newCommitLeft + sizeIncrement; while (pageX > newCommitRectRight) { newCommitRectRight += sizeIncrement; newCommitIndex += 1; } } if (newCommitIndex < 0) { newCommitIndex = 0; } else if (newCommitIndex > maxCommitIndex) { newCommitIndex = maxCommitIndex; } selectCommitIndex(newCommitIndex); } }; useEffect(() => { if (dragState === null) { return; } const element = divRef.current; if (element !== null) { const ownerDocument = element.ownerDocument; ownerDocument.addEventListener('mousemove', handleDragCommit); return () => { ownerDocument.removeEventListener('mousemove', handleDragCommit); }; } }, [dragState]); const [hoveredCommitIndex, setHoveredCommitIndex] = useState<number | null>( null, ); // Pass required contextual data down to the ListItem renderer. const itemData = useMemo<ItemData>( () => ({ commitTimes, filteredCommitIndices, maxDuration, selectedCommitIndex, selectedFilteredCommitIndex, selectCommitIndex, setHoveredCommitIndex, startCommitDrag: setDragState, totalDurations, }), [ commitTimes, filteredCommitIndices, maxDuration, selectedCommitIndex, selectedFilteredCommitIndex, selectCommitIndex, setHoveredCommitIndex, totalDurations, ], ); let tooltipLabel = null; if (hoveredCommitIndex !== null) { const { duration, effectDuration, passiveEffectDuration, priorityLevel, timestamp, } = commitData[hoveredCommitIndex]; // Only some React versions include commit durations. // Show a richer tooltip only for builds that have that info. if ( effectDuration !== null || passiveEffectDuration !== null || priorityLevel !== null ) { tooltipLabel = ( <ul className={styles.TooltipList}> {priorityLevel !== null && ( <li className={styles.TooltipListItem}> <label className={styles.TooltipLabel}>Priority</label> <span className={styles.TooltipValue}>{priorityLevel}</span> </li> )} <li className={styles.TooltipListItem}> <label className={styles.TooltipLabel}>Committed at</label> <span className={styles.TooltipValue}> {formatTime(timestamp)}s </span> </li> <li className={styles.TooltipListItem}> <div className={styles.DurationsWrapper}> <label className={styles.TooltipLabel}>Durations</label> <ul className={styles.DurationsList}> <li className={styles.DurationsListItem}> <label className={styles.DurationsLabel}>Render</label> <span className={styles.DurationsValue}> {formatDuration(duration)}ms </span> </li> {effectDuration !== null && ( <li className={styles.DurationsListItem}> <label className={styles.DurationsLabel}> Layout effects </label> <span className={styles.DurationsValue}> {formatDuration(effectDuration)}ms </span> </li> )} {passiveEffectDuration !== null && ( <li className={styles.DurationsListItem}> <label className={styles.DurationsLabel}> Passive effects </label> <span className={styles.DurationsValue}> {formatDuration(passiveEffectDuration)}ms </span> </li> )} </ul> </div> </li> </ul> ); } else { tooltipLabel = `${formatDuration(duration)}ms at ${formatTime( timestamp, )}s`; } } return ( <Tooltip className={styles.Tooltip} label={tooltipLabel}> <div ref={divRef} style={{height, width}} onMouseLeave={() => setHoveredCommitIndex(null)}> <FixedSizeList className={styles.List} layout="horizontal" height={height} itemCount={filteredCommitIndices.length} itemData={itemData} itemSize={itemSize} ref={(listRef: any) /* Flow bug? */} width={width}> {SnapshotCommitListItem} </FixedSizeList> </div> </Tooltip> ); }