diff --git a/components/apps/FileExplorer/Navigation.tsx b/components/apps/FileExplorer/Navigation.tsx index 38d6ec4e..bd388427 100644 --- a/components/apps/FileExplorer/Navigation.tsx +++ b/components/apps/FileExplorer/Navigation.tsx @@ -23,16 +23,19 @@ import { import useResizeObserver from "hooks/useResizeObserver"; type NavigationProps = { + addressBarRef: React.RefObject; hideSearch: boolean; id: string; + searchBarRef: React.RefObject; }; const CONTEXT_MENU_OFFSET = 3; -const Navigation: FCWithRef = ({ +const Navigation: FC = ({ hideSearch, id, - ref: inputRef, + addressBarRef, + searchBarRef, }) => { const { url: changeUrl, @@ -149,8 +152,8 @@ const Navigation: FCWithRef = ({ > - - {!hideSearch && !removeSearch && } + + {!hideSearch && !removeSearch && } ); }; diff --git a/components/apps/FileExplorer/SearchBar.tsx b/components/apps/FileExplorer/SearchBar.tsx index 716d5ccc..2d39579e 100644 --- a/components/apps/FileExplorer/SearchBar.tsx +++ b/components/apps/FileExplorer/SearchBar.tsx @@ -23,7 +23,10 @@ type SearchBarProps = { const MAX_ENTRIES = 10; -const SearchBar: FC = ({ id }) => { +const SearchBar: FCWithRef = ({ + id, + ref: searchBarRef, +}) => { const [searchTerm, setSearchTerm] = useState(""); const hasUsedSearch = useRef(false); const { @@ -32,14 +35,13 @@ const SearchBar: FC = ({ id }) => { [id]: { url = "" }, }, } = useProcesses(); - const searchBarRef = useRef(null); const results = useSearch(searchTerm); const { contextMenu } = useMenu(); const { fs } = useFileSystem(); const { updateRecentFiles } = useSession(); useEffect(() => { - if (searchBarRef.current && hasUsedSearch.current) { + if (searchBarRef?.current && hasUsedSearch.current) { const getItems = (): Promise => Promise.all( [ @@ -59,7 +61,8 @@ const SearchBar: FC = ({ id }) => { open(pid, { url: infoUrl }); setSearchTerm(""); - if (searchBarRef.current) { + if (searchBarRef?.current) { + // eslint-disable-next-line no-param-reassign searchBarRef.current.value = ""; searchBarRef.current.blur(); } @@ -84,15 +87,16 @@ const SearchBar: FC = ({ id }) => { } }); } - }, [contextMenu, fs, open, results, updateRecentFiles, url]); + }, [contextMenu, fs, open, results, searchBarRef, updateRecentFiles, url]); useEffect(() => { - if (searchBarRef.current) { + if (searchBarRef?.current) { + // eslint-disable-next-line no-param-reassign searchBarRef.current.value = ""; setSearchTerm(""); } // eslint-disable-next-line react-hooks-addons/no-unused-deps - }, [url]); + }, [searchBarRef, url]); return ( diff --git a/components/apps/FileExplorer/index.tsx b/components/apps/FileExplorer/index.tsx index 2129191f..7079ccaf 100644 --- a/components/apps/FileExplorer/index.tsx +++ b/components/apps/FileExplorer/index.tsx @@ -27,13 +27,22 @@ const FileExplorer: FC = ({ id }) => { const { componentWindow, closing, icon = "", url = "" } = process || {}; const { fs, rootFs } = useFileSystem(); const [currentUrl, setCurrentUrl] = useState(url); - const inputRef = useRef(null); + const addressBarRef = useRef(null); + const searchBarRef = useRef(null); const directoryName = basename(url); const mountUrl = getMountUrl(url, rootFs?.mntMap || {}); const onKeyDown = useCallback((event: KeyboardEvent): void => { - if (event.altKey && event.key.toUpperCase() === "D") { + const eventKey = event.key.toUpperCase(); + + if (event.altKey && eventKey === "D") { haltEvent(event); - inputRef.current?.focus(PREVENT_SCROLL); + addressBarRef.current?.focus(PREVENT_SCROLL); + } else if ( + eventKey === "F3" || + (event.ctrlKey && (eventKey === "E" || eventKey === "F")) + ) { + haltEvent(event); + searchBarRef.current?.focus(PREVENT_SCROLL); } else { const fileManagerEntry = (event?.target as HTMLElement)?.querySelector( "ol li button" @@ -102,14 +111,24 @@ const FileExplorer: FC = ({ id }) => { }, [closing, id, componentWindow, setProcessIcon, setProcessUrl, url]); useEffect(() => { - componentWindow?.addEventListener("keydown", onKeyDown); + componentWindow?.addEventListener("keydown", onKeyDown, { + capture: true, + }); - return () => componentWindow?.removeEventListener("keydown", onKeyDown); + return () => + componentWindow?.removeEventListener("keydown", onKeyDown, { + capture: true, + }); }, [componentWindow, onKeyDown]); return url ? ( - + ) : // eslint-disable-next-line unicorn/no-null diff --git a/components/system/Files/FileManager/index.tsx b/components/system/Files/FileManager/index.tsx index 84cabbd9..47cebab7 100644 --- a/components/system/Files/FileManager/index.tsx +++ b/components/system/Files/FileManager/index.tsx @@ -242,7 +242,7 @@ const FileManager: FC = ({ ref={fileManagerRef} $isEmptyFolder={isEmptyFolder} $scrollable={!hideScrolling} - onKeyDown={onKeyDown} + onKeyDownCapture={onKeyDown} {...(readOnly ? { onContextMenu: haltEvent } : { diff --git a/components/system/Files/FileManager/useFileKeyboardShortcuts.ts b/components/system/Files/FileManager/useFileKeyboardShortcuts.ts index af162a35..beafd2cd 100644 --- a/components/system/Files/FileManager/useFileKeyboardShortcuts.ts +++ b/components/system/Files/FileManager/useFileKeyboardShortcuts.ts @@ -31,7 +31,7 @@ const useFileKeyboardShortcuts = ( setView?: (newView: FileManagerViewNames) => void ): KeyboardShortcutEntry => { const { copyEntries, deletePath, moveEntries } = useFileSystem(); - const { url: changeUrl } = useProcesses(); + const { open, url: changeUrl } = useProcesses(); const { openTransferDialog } = useTransferDialog(); const { foregroundId } = useSession(); @@ -58,7 +58,7 @@ const useFileKeyboardShortcuts = ( (event) => { if (isStartMenu) return; - const { ctrlKey, key, target, shiftKey } = event; + const { altKey, ctrlKey, key, target, shiftKey } = event; if (shiftKey) { if (ctrlKey && !isDesktop) { @@ -85,6 +85,18 @@ const useFileKeyboardShortcuts = ( return; } + const onDelete = (): void => { + if (focusedEntries.length > 0) { + haltEvent(event); + focusedEntries.forEach(async (entry) => { + const path = join(url, entry); + + if (await deletePath(path)) updateFiles(undefined, path); + }); + blurEntry(); + } + }; + if (ctrlKey) { const lKey = key.toLowerCase(); @@ -103,6 +115,13 @@ const useFileKeyboardShortcuts = ( haltEvent(event); copyEntries(focusedEntries.map((entry) => join(url, entry))); break; + case "d": + onDelete(); + break; + case "r": + haltEvent(event); + updateFiles(); + break; case "x": haltEvent(event); moveEntries(focusedEntries.map((entry) => join(url, entry))); @@ -114,6 +133,16 @@ const useFileKeyboardShortcuts = ( } break; } + } else if (altKey) { + const lKey = key.toLowerCase(); + + if (lKey === "n") { + haltEvent(event); + open("FileExplorer", { url }); + } else if (key === "Enter" && focusedEntries.length > 0) { + haltEvent(event); + open("Properties", { url: join(url, focusedEntries[0]) }); + } } else { switch (key) { case "F2": @@ -129,15 +158,7 @@ const useFileKeyboardShortcuts = ( } break; case "Delete": - if (focusedEntries.length > 0) { - haltEvent(event); - focusedEntries.forEach(async (entry) => { - const path = join(url, entry); - - if (await deletePath(path)) updateFiles(undefined, path); - }); - blurEntry(); - } + onDelete(); break; case "Backspace": if (id) { @@ -263,6 +284,7 @@ const useFileKeyboardShortcuts = ( isDesktop, isStartMenu, moveEntries, + open, pasteToFolder, setRenaming, setView, diff --git a/components/system/Taskbar/TaskbarEntry/index.tsx b/components/system/Taskbar/TaskbarEntry/index.tsx index a0326dec..558eb5ec 100644 --- a/components/system/Taskbar/TaskbarEntry/index.tsx +++ b/components/system/Taskbar/TaskbarEntry/index.tsx @@ -9,7 +9,7 @@ import { useProcesses } from "contexts/process"; import { useSession } from "contexts/session"; import Button from "styles/common/Button"; import Icon from "styles/common/Icon"; -import { DIV_BUTTON_PROPS } from "utils/constants"; +import { DIV_BUTTON_PROPS, PROCESS_DELIMITER } from "utils/constants"; import { isSafari, label } from "utils/functions"; const PeekWindow = dynamic( @@ -29,9 +29,10 @@ const TaskbarEntry: FC = ({ icon, id, title }) => { const { linkElement, minimize, + open, processes: { [id]: process }, } = useProcesses(); - const { minimized, progress } = process || {}; + const { minimized, progress, singleton } = process || {}; const linkTaskbarEntry = useCallback( (taskbarEntry: HTMLButtonElement | HTMLDivElement | null) => { if (taskbarEntry) linkElement(id, "taskbarEntry", taskbarEntry); @@ -41,11 +42,29 @@ const TaskbarEntry: FC = ({ icon, id, title }) => { const [isPeekVisible, setIsPeekVisible] = useState(false); const hidePeek = useCallback((): void => setIsPeekVisible(false), []); const showPeek = useCallback((): void => setIsPeekVisible(true), []); - const onClick = useCallback((): void => { - if (minimized || isForeground) minimize(id); + const onClick = useCallback>( + (event): void => { + if (event.shiftKey && !singleton) { + const [pid] = id.split(PROCESS_DELIMITER); - setForegroundId(isForeground ? nextFocusableId : id); - }, [id, isForeground, minimize, minimized, nextFocusableId, setForegroundId]); + open(pid); + } else { + if (minimized || isForeground) minimize(id); + + setForegroundId(isForeground ? nextFocusableId : id); + } + }, + [ + id, + isForeground, + minimize, + minimized, + nextFocusableId, + open, + setForegroundId, + singleton, + ] + ); const focusable = useMemo(() => (isSafari() ? DIV_BUTTON_PROPS : {}), []); return (