From 147a66d64e74ae1c5643fffc647f0be4bec854ef Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:29:17 -0700 Subject: [PATCH] Desktop: Accessibility: Fix multi-note selection menu not tab-focusable (#11018) --- .../gui/NoteEditor/NoteTitle/NoteTitleBar.tsx | 33 ++++++++++++++++++- .../gui/NoteList/utils/useOnKeyDown.ts | 9 ++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx b/packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx index f16a5d22a6..91b537bd9d 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { _ } from '@joplin/lib/locale'; import CommandService from '@joplin/lib/services/CommandService'; -import { ChangeEvent, useCallback } from 'react'; +import { ChangeEvent, useCallback, useRef } from 'react'; import NoteToolbar from '../../NoteToolbar/NoteToolbar'; import { buildStyle } from '@joplin/lib/theme'; import time from '@joplin/lib/time'; @@ -75,6 +75,33 @@ function styles_(props: Props) { }); } +const useReselectHandlers = () => { + const lastTitleFocus = useRef([0, 0]); + const lastTitleValue = useRef(''); + + const onTitleBlur: React.FocusEventHandler = useCallback((event) => { + const titleElement = event.currentTarget; + lastTitleFocus.current = [titleElement.selectionStart, titleElement.selectionEnd]; + lastTitleValue.current = titleElement.value; + }, []); + + const onTitleFocus: React.FocusEventHandler = useCallback((event) => { + const titleElement = event.currentTarget; + // By default, focusing the note title bar can cause its content to become selected. We override + // this with a more reasonable default: + if (titleElement.selectionStart === 0 && titleElement.selectionEnd === titleElement.value.length) { + if (lastTitleValue.current !== titleElement.value) { + titleElement.selectionStart = titleElement.value.length; + } else { + titleElement.selectionStart = lastTitleFocus.current[0]; + titleElement.selectionEnd = lastTitleFocus.current[1]; + } + } + }, []); + + return { onTitleBlur, onTitleFocus }; +}; + export default function NoteTitleBar(props: Props) { const styles = styles_(props); @@ -88,6 +115,8 @@ export default function NoteTitleBar(props: Props) { } }, []); + const { onTitleFocus, onTitleBlur } = useReselectHandlers(); + function renderTitleBarDate() { return {time.formatMsToLocal(props.noteUserUpdatedTime)}; } @@ -111,6 +140,8 @@ export default function NoteTitleBar(props: Props) { readOnly={props.disabled} onChange={props.onTitleChange} onKeyDown={onTitleKeydown} + onFocus={onTitleFocus} + onBlur={onTitleBlur} value={props.noteTitle} /> diff --git a/packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts b/packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts index 41f1bed6d8..123fcfcdc0 100644 --- a/packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts +++ b/packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts @@ -153,14 +153,9 @@ const useOnKeyDown = ( announceForAccessibility(!wasCompleted ? _('Complete') : _('Incomplete')); } - if (key === 'Tab') { + if (key === 'Tab' && event.shiftKey) { event.preventDefault(); - - if (event.shiftKey) { - void CommandService.instance().execute('focusElement', 'sideBar'); - } else { - void CommandService.instance().execute('focusElement', 'noteTitle'); - } + void CommandService.instance().execute('focusElement', 'sideBar'); } if (key.toUpperCase() === 'A' && (event.ctrlKey || event.metaKey)) {