mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-28 19:41:33 +02:00
Merge pull request #12999 from overleaf/ii-history-react-file-tree-optimisation
[web] History file tree list items optimisation GitOrigin-RevId: b5e9b72b7df857479db3b2a276e6c064d8f9427a
This commit is contained in:
@@ -1,29 +1,32 @@
|
||||
import { memo } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import HistoryFileTreeItem from './history-file-tree-item'
|
||||
import iconTypeFromName from '../../../file-tree/util/icon-type-from-name'
|
||||
import Icon from '../../../../shared/components/icon'
|
||||
import { useFileTreeItemSelection } from '../../context/hooks/use-file-tree-item-selection'
|
||||
import type { FileDiff } from '../../services/types/file'
|
||||
|
||||
type HistoryFileTreeDocProps = {
|
||||
file: FileDiff
|
||||
name: string
|
||||
selected: boolean
|
||||
onClick: (file: FileDiff) => void
|
||||
onKeyDown: (file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => void
|
||||
}
|
||||
|
||||
export default function HistoryFileTreeDoc({
|
||||
function HistoryFileTreeDoc({
|
||||
file,
|
||||
name,
|
||||
selected,
|
||||
onClick,
|
||||
onKeyDown,
|
||||
}: HistoryFileTreeDocProps) {
|
||||
const { isSelected, handleClick, handleKeyDown } =
|
||||
useFileTreeItemSelection(file)
|
||||
|
||||
return (
|
||||
<li
|
||||
role="treeitem"
|
||||
className={classNames({ selected: isSelected })}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
aria-selected={isSelected}
|
||||
className={classNames({ selected })}
|
||||
onClick={() => onClick(file)}
|
||||
onKeyDown={e => onKeyDown(file, e)}
|
||||
aria-selected={selected}
|
||||
aria-label={name}
|
||||
tabIndex={0}
|
||||
>
|
||||
@@ -41,3 +44,5 @@ export default function HistoryFileTreeDoc({
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(HistoryFileTreeDoc)
|
||||
|
||||
@@ -2,8 +2,10 @@ import classNames from 'classnames'
|
||||
|
||||
import HistoryFileTreeDoc from './history-file-tree-doc'
|
||||
import HistoryFileTreeFolder from './history-file-tree-folder'
|
||||
import type { ReactNode } from 'react'
|
||||
import { ReactNode, useCallback } from 'react'
|
||||
import type { HistoryFileTree, HistoryDoc } from '../../utils/file-tree'
|
||||
import { useHistoryContext } from '../../context/history-context'
|
||||
import { FileDiff } from '../../services/types/file'
|
||||
|
||||
type HistoryFileTreeFolderListProps = {
|
||||
folders: HistoryFileTree[]
|
||||
@@ -12,12 +14,46 @@ type HistoryFileTreeFolderListProps = {
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
export default function HistoryFileTreeFolderList({
|
||||
function HistoryFileTreeFolderList({
|
||||
folders,
|
||||
docs,
|
||||
rootClassName,
|
||||
children,
|
||||
}: HistoryFileTreeFolderListProps) {
|
||||
const { selection, setSelection } = useHistoryContext()
|
||||
|
||||
const handleEvent = useCallback(
|
||||
(file: FileDiff) => {
|
||||
setSelection(prevSelection => {
|
||||
if (file.pathname !== prevSelection.selectedFile?.pathname) {
|
||||
return {
|
||||
...prevSelection,
|
||||
selectedFile: file,
|
||||
}
|
||||
}
|
||||
|
||||
return prevSelection
|
||||
})
|
||||
},
|
||||
[setSelection]
|
||||
)
|
||||
|
||||
const handleClick = useCallback(
|
||||
(file: FileDiff) => {
|
||||
handleEvent(file)
|
||||
},
|
||||
[handleEvent]
|
||||
)
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(file: FileDiff, event: React.KeyboardEvent<HTMLLIElement>) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
handleEvent(file)
|
||||
}
|
||||
},
|
||||
[handleEvent]
|
||||
)
|
||||
|
||||
return (
|
||||
<ul className={classNames('list-unstyled', rootClassName)} role="tree">
|
||||
{folders.map(folder => (
|
||||
@@ -29,9 +65,18 @@ export default function HistoryFileTreeFolderList({
|
||||
/>
|
||||
))}
|
||||
{docs.map(doc => (
|
||||
<HistoryFileTreeDoc key={doc.pathname} name={doc.name} file={doc} />
|
||||
<HistoryFileTreeDoc
|
||||
key={doc.pathname}
|
||||
name={doc.name}
|
||||
file={doc}
|
||||
selected={selection.selectedFile?.pathname === doc.pathname}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
))}
|
||||
{children}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default HistoryFileTreeFolderList
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useState, memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import HistoryFileTreeItem from './history-file-tree-item'
|
||||
@@ -13,7 +13,7 @@ type HistoryFileTreeFolderProps = {
|
||||
docs: HistoryDoc[]
|
||||
}
|
||||
|
||||
export default function HistoryFileTreeFolder({
|
||||
function HistoryFileTreeFolder({
|
||||
name,
|
||||
folders,
|
||||
docs,
|
||||
@@ -61,3 +61,5 @@ export default function HistoryFileTreeFolder({
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(HistoryFileTreeFolder)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useMemo } from 'react'
|
||||
import { orderBy, reduce } from 'lodash'
|
||||
import { useHistoryContext } from '../context/history-context'
|
||||
import {
|
||||
@@ -9,13 +10,26 @@ import HistoryFileTreeFolderList from './file-tree/history-file-tree-folder-list
|
||||
export default function HistoryFileTree() {
|
||||
const { selection, error } = useHistoryContext()
|
||||
|
||||
const fileTree = reduce(selection.files, reducePathsToTree, [])
|
||||
const fileTree = useMemo(
|
||||
() => reduce(selection.files, reducePathsToTree, []),
|
||||
[selection.files]
|
||||
)
|
||||
|
||||
const sortedFileTree = orderBy(fileTree, ['-type', 'operation', 'name'])
|
||||
const sortedFileTree = useMemo(
|
||||
() => orderBy(fileTree, ['-type', 'operation', 'name']),
|
||||
[fileTree]
|
||||
)
|
||||
|
||||
const mappedFileTree = fileTreeDiffToFileTreeData(sortedFileTree)
|
||||
const mappedFileTree = useMemo(
|
||||
() => fileTreeDiffToFileTreeData(sortedFileTree),
|
||||
[sortedFileTree]
|
||||
)
|
||||
|
||||
return error ? null : (
|
||||
if (error) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<HistoryFileTreeFolderList
|
||||
folders={mappedFileTree.folders}
|
||||
docs={mappedFileTree.docs ?? []}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useHistoryContext } from '../history-context'
|
||||
import type { FileDiff } from '../../services/types/file'
|
||||
|
||||
export function useFileTreeItemSelection(file: FileDiff) {
|
||||
const { selection, setSelection } = useHistoryContext()
|
||||
|
||||
const handleEvent = useCallback(() => {
|
||||
if (file.pathname !== selection.selectedFile?.pathname) {
|
||||
setSelection({
|
||||
...selection,
|
||||
selectedFile: file,
|
||||
})
|
||||
}
|
||||
}, [file, selection, setSelection])
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
handleEvent()
|
||||
}, [handleEvent])
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
event => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
handleEvent()
|
||||
}
|
||||
},
|
||||
[handleEvent]
|
||||
)
|
||||
|
||||
const isSelected = selection.selectedFile?.pathname === file.pathname
|
||||
|
||||
return { isSelected, handleClick, handleKeyDown }
|
||||
}
|
||||
Reference in New Issue
Block a user