fix: file popover not closing when click inside editor (#924)

This commit is contained in:
Aman Harwara
2022-03-14 17:30:15 +05:30
committed by GitHub
parent 7e67061097
commit 89c4b9a9f8
4 changed files with 32 additions and 5 deletions

View File

@@ -11,7 +11,7 @@ import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact'; import { FunctionComponent } from 'preact';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { Icon } from '../Icon'; import { Icon } from '../Icon';
import { useCloseOnClickOutside } from '../utils'; import { useCloseOnBlur } from '../utils';
import { import {
ChallengeReason, ChallengeReason,
ContentType, ContentType,
@@ -66,9 +66,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
const buttonRef = useRef<HTMLButtonElement>(null); const buttonRef = useRef<HTMLButtonElement>(null);
const panelRef = useRef<HTMLDivElement>(null); const panelRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
useCloseOnClickOutside(containerRef, () => { const [closeOnBlur, keepMenuOpen] = useCloseOnBlur(containerRef, setOpen);
setOpen(false);
});
const [attachedFilesCount, setAttachedFilesCount] = useState( const [attachedFilesCount, setAttachedFilesCount] = useState(
note ? application.items.getFilesForNote(note).length : 0 note ? application.items.getFilesForNote(note).length : 0
@@ -170,7 +168,10 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
const toggleFileProtection = async (file: SNFile) => { const toggleFileProtection = async (file: SNFile) => {
let result: SNFile | undefined; let result: SNFile | undefined;
if (file.protected) { if (file.protected) {
keepMenuOpen(true);
result = await application.protections.unprotectFile(file); result = await application.protections.unprotectFile(file);
keepMenuOpen(false);
buttonRef.current?.focus();
} else { } else {
result = await application.protections.protectFile(file); result = await application.protections.protectFile(file);
} }
@@ -207,10 +208,13 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
file.protected && file.protected &&
action.type !== PopoverFileItemActionType.ToggleFileProtection action.type !== PopoverFileItemActionType.ToggleFileProtection
) { ) {
keepMenuOpen(true);
isAuthorizedForAction = await authorizeProtectedActionForFile( isAuthorizedForAction = await authorizeProtectedActionForFile(
file, file,
ChallengeReason.AccessProtectedFile ChallengeReason.AccessProtectedFile
); );
keepMenuOpen(false);
buttonRef.current?.focus();
} }
if (!isAuthorizedForAction) { if (!isAuthorizedForAction) {
@@ -354,6 +358,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
className={`sn-icon-button border-contrast ${ className={`sn-icon-button border-contrast ${
attachedFilesCount > 0 ? 'py-1 px-3' : '' attachedFilesCount > 0 ? 'py-1 px-3' : ''
}`} }`}
onBlur={closeOnBlur}
> >
<VisuallyHidden>Attached files</VisuallyHidden> <VisuallyHidden>Attached files</VisuallyHidden>
<Icon type="attachment-file" className="block" /> <Icon type="attachment-file" className="block" />
@@ -374,6 +379,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
maxHeight, maxHeight,
}} }}
className="sn-dropdown sn-dropdown--animated min-w-80 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed" 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 && ( {open && (
<AttachedFilesPopover <AttachedFilesPopover
@@ -382,6 +388,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
note={note} note={note}
handleFileAction={handleFileAction} handleFileAction={handleFileAction}
currentTab={currentTab} currentTab={currentTab}
closeOnBlur={closeOnBlur}
setCurrentTab={setCurrentTab} setCurrentTab={setCurrentTab}
isDraggingFiles={isDraggingFiles} isDraggingFiles={isDraggingFiles}
/> />

View File

@@ -1,3 +1,4 @@
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/constants';
import { WebApplication } from '@/ui_models/application'; import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state'; import { AppState } from '@/ui_models/app_state';
import { ContentType, SNFile, SNNote } from '@standardnotes/snjs'; import { ContentType, SNFile, SNNote } from '@standardnotes/snjs';
@@ -22,6 +23,7 @@ type Props = {
application: WebApplication; application: WebApplication;
appState: AppState; appState: AppState;
currentTab: PopoverTabs; currentTab: PopoverTabs;
closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void;
handleFileAction: (action: PopoverFileItemAction) => Promise<boolean>; handleFileAction: (action: PopoverFileItemAction) => Promise<boolean>;
isDraggingFiles: boolean; isDraggingFiles: boolean;
note: SNNote; note: SNNote;
@@ -33,6 +35,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
application, application,
appState, appState,
currentTab, currentTab,
closeOnBlur,
handleFileAction, handleFileAction,
isDraggingFiles, isDraggingFiles,
note, note,
@@ -100,6 +103,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
return ( return (
<div <div
className="flex flex-col" className="flex flex-col"
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
style={{ style={{
border: isDraggingFiles border: isDraggingFiles
? '2px dashed var(--sn-stylekit-info-color)' ? '2px dashed var(--sn-stylekit-info-color)'
@@ -116,6 +120,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
onClick={() => { onClick={() => {
setCurrentTab(PopoverTabs.AttachedFiles); setCurrentTab(PopoverTabs.AttachedFiles);
}} }}
onBlur={closeOnBlur}
> >
Attached Attached
</button> </button>
@@ -128,6 +133,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
onClick={() => { onClick={() => {
setCurrentTab(PopoverTabs.AllFiles); setCurrentTab(PopoverTabs.AllFiles);
}} }}
onBlur={closeOnBlur}
> >
All files All files
</button> </button>
@@ -144,6 +150,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
onInput={(e) => { onInput={(e) => {
setSearchQuery((e.target as HTMLInputElement).value); setSearchQuery((e.target as HTMLInputElement).value);
}} }}
onBlur={closeOnBlur}
/> />
{searchQuery.length > 0 && ( {searchQuery.length > 0 && (
<button <button
@@ -151,6 +158,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
onClick={() => { onClick={() => {
setSearchQuery(''); setSearchQuery('');
}} }}
onBlur={closeOnBlur}
> >
<Icon <Icon
type="clear-circle-filled" type="clear-circle-filled"
@@ -170,6 +178,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
isAttachedToNote={attachedFiles.includes(file)} isAttachedToNote={attachedFiles.includes(file)}
handleFileAction={handleFileAction} handleFileAction={handleFileAction}
getIconType={application.iconsController.getIconForFileType} getIconType={application.iconsController.getIconForFileType}
closeOnBlur={closeOnBlur}
/> />
); );
}) })
@@ -190,7 +199,11 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
? 'No files attached to this note' ? 'No files attached to this note'
: 'No files found in this account'} : 'No files found in this account'}
</div> </div>
<Button type="normal" onClick={handleAttachFilesClick}> <Button
type="normal"
onClick={handleAttachFilesClick}
onBlur={closeOnBlur}
>
{currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'}{' '} {currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'}{' '}
files files
</Button> </Button>
@@ -204,6 +217,7 @@ export const AttachedFilesPopover: FunctionComponent<Props> = observer(
<button <button
className="sn-dropdown-item py-3 border-0 border-t-1px border-solid border-main focus:bg-info-backdrop" className="sn-dropdown-item py-3 border-0 border-t-1px border-solid border-main focus:bg-info-backdrop"
onClick={handleAttachFilesClick} onClick={handleAttachFilesClick}
onBlur={closeOnBlur}
> >
<Icon type="add" className="mr-2 color-neutral" /> <Icon type="add" className="mr-2 color-neutral" />
{currentTab === PopoverTabs.AttachedFiles {currentTab === PopoverTabs.AttachedFiles

View File

@@ -21,6 +21,7 @@ export type PopoverFileItemProps = {
isAttachedToNote: boolean; isAttachedToNote: boolean;
handleFileAction: (action: PopoverFileItemAction) => Promise<boolean>; handleFileAction: (action: PopoverFileItemAction) => Promise<boolean>;
getIconType(type: string): IconType; getIconType(type: string): IconType;
closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void;
}; };
export const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({ export const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
@@ -28,6 +29,7 @@ export const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
isAttachedToNote, isAttachedToNote,
handleFileAction, handleFileAction,
getIconType, getIconType,
closeOnBlur,
}) => { }) => {
const [fileName, setFileName] = useState(file.name); const [fileName, setFileName] = useState(file.name);
const [isRenamingFile, setIsRenamingFile] = useState(false); const [isRenamingFile, setIsRenamingFile] = useState(false);
@@ -93,6 +95,7 @@ export const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
isAttachedToNote={isAttachedToNote} isAttachedToNote={isAttachedToNote}
handleFileAction={handleFileAction} handleFileAction={handleFileAction}
setIsRenamingFile={setIsRenamingFile} setIsRenamingFile={setIsRenamingFile}
closeOnBlur={closeOnBlur}
/> />
</div> </div>
); );

View File

@@ -25,6 +25,7 @@ type ButtonProps = {
| TargetedEvent<HTMLFormElement> | TargetedEvent<HTMLFormElement>
| TargetedMouseEvent<HTMLButtonElement> | TargetedMouseEvent<HTMLButtonElement>
) => void; ) => void;
onBlur?: (event: FocusEvent) => void;
disabled?: boolean; disabled?: boolean;
}; };
@@ -34,6 +35,7 @@ export const Button: FunctionComponent<ButtonProps> = forwardRef(
type, type,
label, label,
className = '', className = '',
onBlur,
onClick, onClick,
disabled = false, disabled = false,
children, children,
@@ -46,6 +48,7 @@ export const Button: FunctionComponent<ButtonProps> = forwardRef(
return ( return (
<button <button
className={`${buttonClass} ${cursorClass} ${className}`} className={`${buttonClass} ${cursorClass} ${className}`}
onBlur={onBlur}
onClick={(e) => { onClick={(e) => {
onClick(e); onClick(e);
e.preventDefault(); e.preventDefault();