From 5f6feeff00725b3e1603a0c91980569c2be7d663 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 11 Aug 2019 15:38:50 +0800 Subject: [PATCH] feat: scroll to node --- src/components/FileExplorer.tsx | 80 ++++++++++++++++++++------------- src/driver/core/FileExplorer.ts | 28 +++++++----- src/utils/DOMHelper.ts | 18 -------- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index c497ff8..ff11118 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -52,6 +52,54 @@ class FileExplorer extends React.Component { execAfterRender() } + renderFiles(visibleNodes: VisibleNodes) { + const { nodes } = visibleNodes + const { searchKey, focusedNode } = this.props + const inSearch = searchKey !== '' + if (inSearch && nodes.length === 0) { + return + } + return ( + + {({ width = 0, height = 0 }) => ( + + )} + + ) + } + + ListV = React.memo<{ + nodes: TreeNode[] + height: number + width: number + focusedNode: TreeNode | null + }>(({ nodes, width, height, focusedNode }) => { + const listRef = React.useRef(null) + React.useEffect(() => { + const { visibleNodes } = this.props + const nodes = visibleNodes && visibleNodes.nodes + if (nodes && focusedNode && listRef.current) { + listRef.current.scrollToItem(nodes.indexOf(focusedNode), 'smart') + } + }, [listRef.current, focusedNode]) + return ( + { + const node = nodes[index] + return node && node.path + }} + itemData={{ nodes }} + itemCount={nodes.length} + itemSize={35} + height={height} + width={width} + > + {this.VirtualNode} + + ) + }) + VirtualNode = React.memo(({ index, style }) => { const { visibleNodes, onNodeClick } = this.props if (!visibleNodes) return null @@ -71,37 +119,6 @@ class FileExplorer extends React.Component { ) }) - renderFiles(visibleNodes: VisibleNodes) { - const { nodes } = visibleNodes - const { searchKey } = this.props - const inSearch = searchKey !== '' - if (inSearch && nodes.length === 0) { - return - } - return ( - - {({ width, height }) => - height && - width && ( - { - const node = nodes[index] - return node && node.path - }} - itemData={{ nodes }} - height={height} - itemCount={nodes.length} - itemSize={35} - width={width} - > - {this.VirtualNode} - - ) - } - - ) - } - private renderActions: Node['props']['renderActions'] = node => { const { searchKey, searched, goTo } = this.props return ( @@ -135,7 +152,6 @@ class FileExplorer extends React.Component { freeze, handleKeyDown, handleSearchKeyChange, - onNodeClick, toggleShowSettings, onFocusSearchBar, searchKey, diff --git a/src/driver/core/FileExplorer.ts b/src/driver/core/FileExplorer.ts index cc6fa37..d162515 100644 --- a/src/driver/core/FileExplorer.ts +++ b/src/driver/core/FileExplorer.ts @@ -16,6 +16,7 @@ export type ConnectorState = { visibleNodes: VisibleNodes | null searchKey: string searched: boolean + focusedNode: TreeNode | null init: () => void execAfterRender: () => void @@ -307,14 +308,17 @@ const search: MethodCreator = dispatch => { const goTo: MethodCreator = dispatch => async currentPath => { await visibleNodesGenerator.search('') + tasksAfterRender.push(() => { + const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/')) + if (nodeExpandedTo) { + visibleNodesGenerator.focusNode(nodeExpandedTo) + dispatch.set({ + focusedNode: nodeExpandedTo, + }) + } + dispatch.call(updateVisibleNodes) + }) dispatch.set({ searchKey: '', searched: false }) - const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/')) - if (nodeExpandedTo) { - visibleNodesGenerator.focusNode(nodeExpandedTo) - const { nodes } = visibleNodesGenerator.visibleNodes - tasksAfterRender.push(() => DOMHelper.scrollToNodeElement(nodes.indexOf(nodeExpandedTo))) - } - dispatch.call(updateVisibleNodes) } const setExpand: MethodCreator = dispatch => ( @@ -330,8 +334,8 @@ const toggleNodeExpansion: MethodCreator { visibleNodesGenerator.toggleExpand(node) - dispatch.call(focusNode, node, skipScrollToNode) - tasksAfterRender.push(DOMHelper.focusFileExplorer) + dispatch.call(focusNode, node, skipScrollToNode) + tasksAfterRender.push(DOMHelper.focusFileExplorer) } const focusNode: MethodCreator = dispatch => ( @@ -340,12 +344,12 @@ const focusNode: MethodCreator dispatch.get(({ visibleNodes }) => { if (!visibleNodes) return - const { nodes } = visibleNodes visibleNodesGenerator.focusNode(node) if (node && !skipScroll) { // when focus a node not in viewport(by keyboard), scroll to it - const indexOfToBeFocusedNode = nodes.indexOf(node) - tasksAfterRender.push(() => DOMHelper.scrollToNodeElement(indexOfToBeFocusedNode)) + dispatch.set({ + focusedNode: node, + }) } dispatch.call(updateVisibleNodes) }) diff --git a/src/utils/DOMHelper.ts b/src/utils/DOMHelper.ts index fb4ddba..05cc185 100644 --- a/src/utils/DOMHelper.ts +++ b/src/utils/DOMHelper.ts @@ -118,23 +118,6 @@ function scrollToRepoContent() { ) } -/** - * scroll to index-th element in the list - */ -function scrollToNodeElement(index: number) { - const nodeElementSelector = '.node-item' - const nodeElements = document.querySelectorAll(nodeElementSelector) - const targetElement = nodeElements[index] - if (targetElement) { - targetElement.scrollIntoView({ - behavior: 'smooth', - block: 'center', - }) - } else { - raiseError(new Error('cannot find DOM node to scroll to')) - } -} - const pjax = new PJAX({ elements: '.pjax-link', selectors: ['.repository-content', 'title'], @@ -411,7 +394,6 @@ export default { insertLogoMountPoint, markGitakoReadyState, setBodyIndent, - scrollToNodeElement, scrollToRepoContent, mountTopProgressBar, unmountTopProgressBar,