diff --git a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesButton.tsx b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesButton.tsx index acaa042b8..208e13949 100644 --- a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesButton.tsx +++ b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesButton.tsx @@ -11,7 +11,7 @@ import { observer } from 'mobx-react-lite'; import { FunctionComponent } from 'preact'; import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; import { Icon } from '../Icon'; -import { useCloseOnClickOutside } from '../utils'; +import { useCloseOnBlur } from '../utils'; import { ChallengeReason, ContentType, @@ -66,9 +66,7 @@ export const AttachedFilesButton: FunctionComponent = observer( const buttonRef = useRef(null); const panelRef = useRef(null); const containerRef = useRef(null); - useCloseOnClickOutside(containerRef, () => { - setOpen(false); - }); + const [closeOnBlur, keepMenuOpen] = useCloseOnBlur(containerRef, setOpen); const [attachedFilesCount, setAttachedFilesCount] = useState( note ? application.items.getFilesForNote(note).length : 0 @@ -170,7 +168,10 @@ export const AttachedFilesButton: FunctionComponent = observer( const toggleFileProtection = async (file: SNFile) => { let result: SNFile | undefined; if (file.protected) { + keepMenuOpen(true); result = await application.protections.unprotectFile(file); + keepMenuOpen(false); + buttonRef.current?.focus(); } else { result = await application.protections.protectFile(file); } @@ -207,10 +208,13 @@ export const AttachedFilesButton: FunctionComponent = observer( file.protected && action.type !== PopoverFileItemActionType.ToggleFileProtection ) { + keepMenuOpen(true); isAuthorizedForAction = await authorizeProtectedActionForFile( file, ChallengeReason.AccessProtectedFile ); + keepMenuOpen(false); + buttonRef.current?.focus(); } if (!isAuthorizedForAction) { @@ -354,6 +358,7 @@ export const AttachedFilesButton: FunctionComponent = observer( className={`sn-icon-button border-contrast ${ attachedFilesCount > 0 ? 'py-1 px-3' : '' }`} + onBlur={closeOnBlur} > Attached files @@ -374,6 +379,7 @@ export const AttachedFilesButton: FunctionComponent = observer( maxHeight, }} className="sn-dropdown sn-dropdown--animated min-w-80 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed" + onBlur={closeOnBlur} > {open && ( = observer( note={note} handleFileAction={handleFileAction} currentTab={currentTab} + closeOnBlur={closeOnBlur} setCurrentTab={setCurrentTab} isDraggingFiles={isDraggingFiles} /> diff --git a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx index 1515e5307..48b3f034b 100644 --- a/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx +++ b/app/assets/javascripts/components/AttachedFilesPopover/AttachedFilesPopover.tsx @@ -1,3 +1,4 @@ +import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/constants'; import { WebApplication } from '@/ui_models/application'; import { AppState } from '@/ui_models/app_state'; import { ContentType, SNFile, SNNote } from '@standardnotes/snjs'; @@ -22,6 +23,7 @@ type Props = { application: WebApplication; appState: AppState; currentTab: PopoverTabs; + closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void; handleFileAction: (action: PopoverFileItemAction) => Promise; isDraggingFiles: boolean; note: SNNote; @@ -33,6 +35,7 @@ export const AttachedFilesPopover: FunctionComponent = observer( application, appState, currentTab, + closeOnBlur, handleFileAction, isDraggingFiles, note, @@ -100,6 +103,7 @@ export const AttachedFilesPopover: FunctionComponent = observer( return (
= observer( onClick={() => { setCurrentTab(PopoverTabs.AttachedFiles); }} + onBlur={closeOnBlur} > Attached @@ -128,6 +133,7 @@ export const AttachedFilesPopover: FunctionComponent = observer( onClick={() => { setCurrentTab(PopoverTabs.AllFiles); }} + onBlur={closeOnBlur} > All files @@ -144,6 +150,7 @@ export const AttachedFilesPopover: FunctionComponent = observer( onInput={(e) => { setSearchQuery((e.target as HTMLInputElement).value); }} + onBlur={closeOnBlur} /> {searchQuery.length > 0 && (
- @@ -204,6 +217,7 @@ export const AttachedFilesPopover: FunctionComponent = observer(