|
|
|
@ -1,14 +1,15 @@ |
|
|
|
|
import React, { SyntheticEvent, useEffect, useRef, useState, RefObject, useMemo } from 'react' |
|
|
|
|
import React, { SyntheticEvent, useEffect, useRef, useState, RefObject, useMemo, useContext, Dispatch } from 'react' |
|
|
|
|
import { Popover } from 'react-bootstrap' |
|
|
|
|
import { FileType, WorkspaceElement } from '../types' |
|
|
|
|
import { DragStructure, FileType, WorkspaceElement } from '../types' |
|
|
|
|
import { getPathIcon } from '@remix-ui/helper'; |
|
|
|
|
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso' |
|
|
|
|
import { FlatTreeItemInput } from './flat-tree-item-input'; |
|
|
|
|
import { FlatTreeDrop } from './flat-tree-drop'; |
|
|
|
|
import { getEventTarget } from '../utils/getEventTarget'; |
|
|
|
|
import { buildMultiSelectedItemProfiles, getEventTarget } from '../utils/getEventTarget'; |
|
|
|
|
import { fileDecoration, FileDecorationIcons } from '@remix-ui/file-decorators'; |
|
|
|
|
import { FileHoverIcons } from './file-explorer-hovericons'; |
|
|
|
|
import { deletePath } from '../actions'; |
|
|
|
|
import { FileSystemContext } from '../contexts'; |
|
|
|
|
|
|
|
|
|
export default function useOnScreen(ref: RefObject<HTMLElement>) { |
|
|
|
|
|
|
|
|
@ -35,13 +36,16 @@ interface FlatTreeProps { |
|
|
|
|
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void |
|
|
|
|
handleTreeClick: (e: SyntheticEvent) => void |
|
|
|
|
handleClickFolder: (path: string, type: string) => void |
|
|
|
|
moveFile: (dest: string, src: string) => void |
|
|
|
|
moveFolder: (dest: string, src: string) => void |
|
|
|
|
moveFolderSilently: (dest: string, src: string) => Promise<void> |
|
|
|
|
moveFileSilently: (dest: string, src: string) => Promise<void> |
|
|
|
|
resetMultiselect: () => void |
|
|
|
|
setFilesSelected: Dispatch<React.SetStateAction<string[]>> |
|
|
|
|
fileState: fileDecoration[] |
|
|
|
|
createNewFile?: any |
|
|
|
|
createNewFolder?: any |
|
|
|
|
deletePath?: (path: string | string[]) => void | Promise<void> |
|
|
|
|
editPath?: (path: string, type: string, isNew?: boolean) => void |
|
|
|
|
warnMovingItems: (srcs: string[], dests: string) => Promise<void> |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mouseTimer: any = { |
|
|
|
@ -50,7 +54,7 @@ let mouseTimer: any = { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export const FlatTree = (props: FlatTreeProps) => { |
|
|
|
|
const { files, flatTree, expandPath, focusEdit, editModeOff, handleTreeClick, moveFile, moveFolder, fileState, focusElement, handleClickFolder, deletePath, editPath } = props |
|
|
|
|
const { files, flatTree, expandPath, focusEdit, editModeOff, handleTreeClick, warnMovingItems, fileState, focusElement, handleClickFolder, deletePath, moveFileSilently, moveFolderSilently, setFilesSelected } = props |
|
|
|
|
const [hover, setHover] = useState<string>('') |
|
|
|
|
const [mouseOverTarget, setMouseOverTarget] = useState<{ |
|
|
|
|
path: string, |
|
|
|
@ -67,12 +71,13 @@ export const FlatTree = (props: FlatTreeProps) => { |
|
|
|
|
const ref = useRef(null) |
|
|
|
|
const containerRef = useRef<HTMLDivElement>(null) |
|
|
|
|
const virtuoso = useRef<VirtuosoHandle>(null) |
|
|
|
|
const [selectedItems, setSelectedItems] = useState<DragStructure[]>([]) |
|
|
|
|
|
|
|
|
|
const labelClass = (file: FileType) => |
|
|
|
|
props.focusEdit.element === file.path |
|
|
|
|
? 'bg-light' |
|
|
|
|
: props.focusElement.findIndex((item) => item.key === file.path) !== -1 |
|
|
|
|
? 'bg-secondary' |
|
|
|
|
? 'bg-secondary remixui_selected' |
|
|
|
|
: hover == file.path |
|
|
|
|
? 'bg-light border-no-shift' |
|
|
|
|
: props.focusContext.element === file.path && props.focusEdit.element !== file.path |
|
|
|
@ -103,6 +108,9 @@ export const FlatTree = (props: FlatTreeProps) => { |
|
|
|
|
const target = await getEventTarget(event) |
|
|
|
|
setDragSource(flatTree.find((item) => item.path === target.path)) |
|
|
|
|
setIsDragging(true) |
|
|
|
|
const items = buildMultiSelectedItemProfiles(target) |
|
|
|
|
setSelectedItems(items) |
|
|
|
|
setFilesSelected(items.map((item) => item.path)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
@ -116,6 +124,12 @@ export const FlatTree = (props: FlatTreeProps) => { |
|
|
|
|
|
|
|
|
|
const onDragEnd = (event: SyntheticEvent) => { |
|
|
|
|
setIsDragging(false) |
|
|
|
|
document.querySelectorAll('li.remixui_selected').forEach(item => { |
|
|
|
|
item.classList.remove('remixui_selected') |
|
|
|
|
item.classList.remove('bg-secondary') |
|
|
|
|
}) |
|
|
|
|
props.setFilesSelected([]) |
|
|
|
|
setSelectedItems([]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const getFlatTreeItem = (path: string) => { |
|
|
|
@ -247,17 +261,23 @@ export const FlatTree = (props: FlatTreeProps) => { |
|
|
|
|
<FlatTreeDrop |
|
|
|
|
dragSource={dragSource} |
|
|
|
|
getFlatTreeItem={getFlatTreeItem} |
|
|
|
|
moveFile={moveFile} |
|
|
|
|
moveFolder={moveFolder} |
|
|
|
|
warnMovingItems={warnMovingItems} |
|
|
|
|
moveFolderSilently={moveFolderSilently} |
|
|
|
|
moveFileSilently={moveFileSilently} |
|
|
|
|
resetMultiselect={props.resetMultiselect} |
|
|
|
|
setFilesSelected={setFilesSelected} |
|
|
|
|
handleClickFolder={handleClickFolder} |
|
|
|
|
expandPath={expandPath} |
|
|
|
|
selectedItems={selectedItems} |
|
|
|
|
setSelectedItems={setSelectedItems} |
|
|
|
|
> |
|
|
|
|
<div data-id="treeViewUltreeViewMenu" |
|
|
|
|
className='d-flex h-100 w-100 pb-2' |
|
|
|
|
onClick={handleTreeClick} |
|
|
|
|
onMouseLeave={onMouseLeave} |
|
|
|
|
onMouseMove={onMouseMove} |
|
|
|
|
onContextMenu={handleContextMenu}> |
|
|
|
|
onContextMenu={handleContextMenu} |
|
|
|
|
> |
|
|
|
|
{ showMouseOverTarget && mouseOverTarget && !isDragging && |
|
|
|
|
<Popover id='popover-basic' |
|
|
|
|
placement='top' |
|
|
|
|