From 1f5d235cd47deb85bd8a0912f316398de41ae68b Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Tue, 1 Feb 2022 20:12:57 +0530 Subject: [PATCH] fix: notes list options menu not toggling correctly (#840) --- .../components/NotesListOptionsMenu.tsx | 21 +++-- .../javascripts/components/NotesView.tsx | 76 ++++++++++++------- .../javascripts/components/menu/MenuItem.tsx | 35 +++++---- .../ui_models/app_state/notes_view_state.ts | 8 +- app/assets/stylesheets/_sn.scss | 4 + 5 files changed, 93 insertions(+), 51 deletions(-) diff --git a/app/assets/javascripts/components/NotesListOptionsMenu.tsx b/app/assets/javascripts/components/NotesListOptionsMenu.tsx index 8d10e9051..be82179c5 100644 --- a/app/assets/javascripts/components/NotesListOptionsMenu.tsx +++ b/app/assets/javascripts/components/NotesListOptionsMenu.tsx @@ -6,19 +6,19 @@ import { useRef, useState } from 'preact/hooks'; import { Icon } from './Icon'; import { Menu } from './menu/Menu'; import { MenuItem, MenuItemSeparator, MenuItemType } from './menu/MenuItem'; -import { useCloseOnClickOutside } from './utils'; type Props = { application: WebApplication; + closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void; closeDisplayOptionsMenu: () => void; }; export const NotesListOptionsMenu: FunctionComponent = observer( - ({ closeDisplayOptionsMenu, application }) => { + ({ closeDisplayOptionsMenu, closeOnBlur, application }) => { const menuClassName = 'sn-dropdown sn-dropdown--animated min-w-70 overflow-y-auto \ border-1 border-solid border-main text-sm z-index-dropdown-menu \ -flex flex-col py-2 bottom-0 left-2 absolute'; +flex flex-col py-2 top-full bottom-0 left-2 absolute'; const [sortBy, setSortBy] = useState(() => application.getPreference(PrefKey.SortNotesBy, CollectionSort.CreatedAt) ); @@ -118,10 +118,6 @@ flex flex-col py-2 bottom-0 left-2 absolute'; const menuRef = useRef(null); - useCloseOnClickOutside(menuRef, () => { - closeDisplayOptionsMenu(); - }); - return (
@@ -133,6 +129,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; type={MenuItemType.RadioButton} onClick={toggleSortByDateModified} checked={sortBy === CollectionSort.UpdatedAt} + onBlur={closeOnBlur} >
Date modified @@ -150,6 +147,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; type={MenuItemType.RadioButton} onClick={toggleSortByCreationDate} checked={sortBy === CollectionSort.CreatedAt} + onBlur={closeOnBlur} >
Creation date @@ -167,6 +165,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; type={MenuItemType.RadioButton} onClick={toggleSortByTitle} checked={sortBy === CollectionSort.Title} + onBlur={closeOnBlur} >
Title @@ -188,6 +187,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hidePreview} onChange={toggleHidePreview} + onBlur={closeOnBlur} >
Show note preview
@@ -196,6 +196,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hideDate} onChange={toggleHideDate} + onBlur={closeOnBlur} > Show date @@ -204,6 +205,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hideTags} onChange={toggleHideTags} + onBlur={closeOnBlur} > Show tags @@ -212,6 +214,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hideEditorIcon} onChange={toggleEditorIcon} + onBlur={closeOnBlur} > Show editor icon @@ -224,6 +227,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hidePinned} onChange={toggleHidePinned} + onBlur={closeOnBlur} > Show pinned notes @@ -232,6 +236,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={!hideProtected} onChange={toggleHideProtected} + onBlur={closeOnBlur} > Show protected notes @@ -240,6 +245,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={showArchived} onChange={toggleShowArchived} + onBlur={closeOnBlur} > Show archived notes @@ -248,6 +254,7 @@ flex flex-col py-2 bottom-0 left-2 absolute'; className="py-1 hover:bg-contrast focus:bg-info-backdrop" checked={showTrashed} onChange={toggleShowTrashed} + onBlur={closeOnBlur} > Show trashed notes diff --git a/app/assets/javascripts/components/NotesView.tsx b/app/assets/javascripts/components/NotesView.tsx index 2e4c1e157..6969ab49c 100644 --- a/app/assets/javascripts/components/NotesView.tsx +++ b/app/assets/javascripts/components/NotesView.tsx @@ -5,7 +5,7 @@ import { PANEL_NAME_NOTES } from '@/views/constants'; import { PrefKey } from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; import { FunctionComponent } from 'preact'; -import { useEffect, useRef } from 'preact/hooks'; +import { useEffect, useRef, useState } from 'preact/hooks'; import { NoAccountWarning } from './NoAccountWarning'; import { NotesList } from './NotesList'; import { NotesListOptionsMenu } from './NotesListOptionsMenu'; @@ -16,6 +16,12 @@ import { PanelResizer, PanelResizeType, } from './PanelResizer'; +import { + Disclosure, + DisclosureButton, + DisclosurePanel, +} from '@reach/disclosure'; +import { useCloseOnBlur } from './utils'; type Props = { application: WebApplication; @@ -25,6 +31,7 @@ type Props = { export const NotesView: FunctionComponent = observer( ({ application, appState }) => { const notesViewPanelRef = useRef(null); + const displayOptionsMenuRef = useRef(null); const { completedFullSync, @@ -36,8 +43,6 @@ export const NotesView: FunctionComponent = observer( renderedNotes, selectedNotes, setNoteFilterText, - showDisplayOptionsMenu, - toggleDisplayOptionsMenu, searchBarElement, selectNextNote, selectPreviousNote, @@ -49,6 +54,13 @@ export const NotesView: FunctionComponent = observer( panelWidth, } = appState.notesView; + const [showDisplayOptionsMenu, setShowDisplayOptionsMenu] = useState(false); + + const [closeDisplayOptMenuOnBlur] = useCloseOnBlur( + displayOptionsMenuRef, + setShowDisplayOptionsMenu + ); + useEffect(() => { handleFilterTextChanged(); }, [noteFilterText, handleFilterTextChanged]); @@ -139,6 +151,10 @@ export const NotesView: FunctionComponent = observer( appState.noteTags.reloadTagsContainerMaxWidth(); }; + const toggleDisplayOptionsMenu = () => { + setShowDisplayOptionsMenu(!showDisplayOptionsMenu); + }; + return (
= observer(
-
+
-
- toggleDisplayOptionsMenu(!showDisplayOptionsMenu) - } + -
-
Options
-
-
-
{optionsSubtitle}
-
-
+ +
+
Options
+
+
+
{optionsSubtitle}
+
+
+ + {showDisplayOptionsMenu && ( + + )} + +
- {showDisplayOptionsMenu && ( - - toggleDisplayOptionsMenu(false) - } - /> - )}
{completedFullSync && !renderedNotes.length ? ( diff --git a/app/assets/javascripts/components/menu/MenuItem.tsx b/app/assets/javascripts/components/menu/MenuItem.tsx index c5643f1f6..4db5d8188 100644 --- a/app/assets/javascripts/components/menu/MenuItem.tsx +++ b/app/assets/javascripts/components/menu/MenuItem.tsx @@ -1,14 +1,10 @@ -import { - ComponentChild, - ComponentChildren, - FunctionComponent, - VNode, -} from 'preact'; +import { ComponentChildren, FunctionComponent, VNode } from 'preact'; import { forwardRef, Ref } from 'preact/compat'; import { JSXInternal } from 'preact/src/jsx'; import { Icon } from '../Icon'; import { Switch, SwitchProps } from '../Switch'; import { IconType } from '@standardnotes/snjs'; +import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/views/constants'; export enum MenuItemType { IconButton, @@ -21,6 +17,7 @@ type MenuItemProps = { children: ComponentChildren; onClick?: JSXInternal.MouseEventHandler; onChange?: SwitchProps['onChange']; + onBlur?: (event: { relatedTarget: EventTarget | null }) => void; className?: string; checked?: boolean; icon?: IconType; @@ -34,6 +31,7 @@ export const MenuItem: FunctionComponent = forwardRef( children, onClick, onChange, + onBlur, className = '', type, checked, @@ -45,22 +43,31 @@ export const MenuItem: FunctionComponent = forwardRef( ) => { return type === MenuItemType.SwitchButton && typeof onChange === 'function' ? ( - { + onChange(!checked); + }} + onBlur={onBlur} + tabIndex={ + typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE + } role="menuitemcheckbox" - tabIndex={typeof tabIndex === 'number' ? tabIndex : -1} + aria-checked={checked} > - {children} - + {children} + + ) : (