pseudo focus

This commit is contained in:
Manav Rathi
2025-03-06 09:09:15 +05:30
parent b1c680cccd
commit c96f2495ed
2 changed files with 63 additions and 30 deletions

View File

@@ -17,10 +17,7 @@ import { isDesktop } from "@/base/app";
import { SpacedRow } from "@/base/components/containers";
import { DialogCloseIconButton } from "@/base/components/mui/DialogCloseIconButton";
import { useIsSmallWidth } from "@/base/components/utils/hooks";
import {
useModalVisibility,
type ModalVisibilityProps,
} from "@/base/components/utils/modal";
import { type ModalVisibilityProps } from "@/base/components/utils/modal";
import { useBaseContext } from "@/base/context";
import { lowercaseExtension } from "@/base/file-name";
import { pt } from "@/base/i18n";
@@ -319,14 +316,11 @@ const FileViewer: React.FC<FileViewerProps> = ({
const [moreMenuAnchorEl, setMoreMenuAnchorEl] =
useState<HTMLElement | null>(null);
const [openImageEditor, setOpenImageEditor] = useState(false);
const [openConfirmDelete, setOpenConfirmDelete] = useState(false);
const [openShortcuts, setOpenShortcuts] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
const { show: showConfirmDelete, props: confirmDeleteVisibilityProps } =
useModalVisibility();
const { show: showShortcuts, props: shortcutsVisibilityProps } =
useModalVisibility();
// Callbacks to be invoked (only once) the next time we get an update to the
// `files` or `favoriteFileIDs` props.
//
@@ -359,10 +353,12 @@ const FileViewer: React.FC<FileViewerProps> = ({
return false;
});
setOpenFileInfo(false);
setOpenImageEditor(false);
// No need to `resetMoreMenuButtonOnMenuClose` since we're closing
// anyway and it'll be removed from the DOM.
setMoreMenuAnchorEl(null);
setOpenImageEditor(false);
setOpenConfirmDelete(false);
setOpenShortcuts(false);
onClose();
}, [onTriggerSyncWithRemote, onClose]);
@@ -424,10 +420,15 @@ const FileViewer: React.FC<FileViewerProps> = ({
return onDelete
? () => {
handleMoreMenuCloseIfNeeded();
showConfirmDelete();
setOpenConfirmDelete(true);
}
: undefined;
}, [onDelete, showConfirmDelete, handleMoreMenuCloseIfNeeded]);
}, [onDelete, handleMoreMenuCloseIfNeeded]);
const handleConfirmDeleteClose = useCallback(
() => setOpenConfirmDelete(false),
[],
);
// Not memoized since it uses the frequently changing `activeAnnotatedFile`.
const handleDelete = async () => {
@@ -626,8 +627,27 @@ const FileViewer: React.FC<FileViewerProps> = ({
const handleShortcuts = useCallback(() => {
handleMoreMenuCloseIfNeeded();
showShortcuts();
}, [handleMoreMenuCloseIfNeeded, showShortcuts]);
setOpenShortcuts(true);
}, [handleMoreMenuCloseIfNeeded]);
const handleShortcutsClose = useCallback(() => setOpenShortcuts(false), []);
const shouldIgnoreKeyboardEvent = useCallback(() => {
// Don't handle keydowns if any of the modals are open.
return (
openFileInfo ||
moreMenuAnchorEl ||
openImageEditor ||
openConfirmDelete ||
openShortcuts
);
}, [
openFileInfo,
moreMenuAnchorEl,
openImageEditor,
openConfirmDelete,
openShortcuts,
]);
const performKeyAction = useCallback(
(action): FileViewerPhotoSwipeDelegate["performKeyAction"] => {
@@ -657,6 +677,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
getFiles,
isFavorite,
toggleFavorite,
shouldIgnoreKeyboardEvent,
performKeyAction,
};
}
@@ -667,8 +688,15 @@ const FileViewer: React.FC<FileViewerProps> = ({
delegate.getFiles = getFiles;
delegate.isFavorite = isFavorite;
delegate.toggleFavorite = toggleFavorite;
delegate.shouldIgnoreKeyboardEvent = shouldIgnoreKeyboardEvent;
delegate.performKeyAction = performKeyAction;
}, [getFiles, isFavorite, toggleFavorite, performKeyAction]);
}, [
getFiles,
isFavorite,
toggleFavorite,
shouldIgnoreKeyboardEvent,
performKeyAction,
]);
// Notify the listeners, if any, for updates to files or favorites.
useEffect(() => {
@@ -822,7 +850,8 @@ const FileViewer: React.FC<FileViewerProps> = ({
</MoreMenu>
{/* TODO(PS): Fix imports */}
<ConfirmDeleteFileDialog
{...confirmDeleteVisibilityProps}
open={openConfirmDelete}
onClose={handleConfirmDeleteClose}
onConfirm={handleDelete}
/>
<ImageEditorOverlay
@@ -831,7 +860,7 @@ const FileViewer: React.FC<FileViewerProps> = ({
file={activeAnnotatedFile?.file}
onSaveEditedCopy={handleSaveEditedCopy}
/>
<Shortcuts {...shortcutsVisibilityProps} />
<Shortcuts open={openShortcuts} onClose={handleShortcutsClose} />
</Container>
);
};

View File

@@ -73,6 +73,14 @@ export interface FileViewerPhotoSwipeDelegate {
* > remain in the disabled state (until the file viewer is closed).
*/
toggleFavorite: (annotatedFile: FileViewerAnnotatedFile) => Promise<void>;
/**
* Called when there is a keydown event, and our PhotoSwipe instance wants
* to know if it should ignore it or handle it.
*
* The delegate should return true when, e.g., the file info dialog is
* being displayed.
*/
shouldIgnoreKeyboardEvent: () => boolean;
/**
* Called when the user triggers a potential action using a keyboard
* shortcut.
@@ -734,22 +742,18 @@ export class FileViewerPhotoSwipe {
const handleToggleFullscreen = () =>
delegate.performKeyAction("toggle-fullscreen");
pswp.on("keydown", (_e) => {
const e: KeyboardEvent = _e.originalEvent;
pswp.on("keydown", (pswpEvent) => {
// Ignore keyboard events when we do not have "focus".
if (delegate.shouldIgnoreKeyboardEvent()) {
pswpEvent.preventDefault();
return;
}
const e: KeyboardEvent = pswpEvent.originalEvent;
// Even though we ignore shift, Caps lock might still be on.
const key = e.key.toLowerCase();
console.log(
e,
key,
e.shiftKey,
e.altKey,
e.metaKey,
e.ctrlKey,
e.code,
);
// Keep the keybindings such that they don't use modifiers, because
// these are more likely to interfere with browser shortcuts.
//