You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-23 22:36:32 +02:00
Desktop: Accessibility: Add a new shortcut to set focus to editor toolbar (#11764)
This commit is contained in:
@@ -272,6 +272,7 @@ packages/app-desktop/gui/NoteEditor/WarningBanner/BannerContent.js
|
|||||||
packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.js
|
packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
||||||
|
packages/app-desktop/gui/NoteEditor/commands/focusElementToolbar.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/index.js
|
packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -247,6 +247,7 @@ packages/app-desktop/gui/NoteEditor/WarningBanner/BannerContent.js
|
|||||||
packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.js
|
packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.js
|
||||||
|
packages/app-desktop/gui/NoteEditor/commands/focusElementToolbar.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/index.js
|
packages/app-desktop/gui/NoteEditor/commands/index.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
packages/app-desktop/gui/NoteEditor/commands/pasteAsText.js
|
||||||
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.js
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const runtime = (): CommandRuntime => {
|
|||||||
if (target === 'noteList') return CommandService.instance().execute('focusElementNoteList');
|
if (target === 'noteList') return CommandService.instance().execute('focusElementNoteList');
|
||||||
if (target === 'sideBar') return CommandService.instance().execute('focusElementSideBar');
|
if (target === 'sideBar') return CommandService.instance().execute('focusElementSideBar');
|
||||||
if (target === 'noteTitle') return CommandService.instance().execute('focusElementNoteTitle', options);
|
if (target === 'noteTitle') return CommandService.instance().execute('focusElementNoteTitle', options);
|
||||||
|
if (target === 'toolbar') return CommandService.instance().execute('focusElementToolbar', options);
|
||||||
throw new Error(`Invalid focus target: ${target}`);
|
throw new Error(`Invalid focus target: ${target}`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ function useMenu(props: Props) {
|
|||||||
menuItemDic.focusElementNoteList,
|
menuItemDic.focusElementNoteList,
|
||||||
menuItemDic.focusElementNoteTitle,
|
menuItemDic.focusElementNoteTitle,
|
||||||
menuItemDic.focusElementNoteBody,
|
menuItemDic.focusElementNoteBody,
|
||||||
|
menuItemDic.focusElementToolbar,
|
||||||
];
|
];
|
||||||
|
|
||||||
const importItems = [];
|
const importItems = [];
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ function Toolbar(props: ToolbarProps) {
|
|||||||
const styles = styles_(props);
|
const styles = styles_(props);
|
||||||
return (
|
return (
|
||||||
<ToolbarBase
|
<ToolbarBase
|
||||||
|
id="CodeMirrorToolbar"
|
||||||
style={styles.root}
|
style={styles.root}
|
||||||
scrollable={true}
|
scrollable={true}
|
||||||
items={props.toolbarButtonInfos}
|
items={props.toolbarButtonInfos}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { CommandRuntime, CommandDeclaration } from '@joplin/lib/services/CommandService';
|
||||||
|
import { _ } from '@joplin/lib/locale';
|
||||||
|
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||||
|
import { WindowCommandDependencies } from '../utils/types';
|
||||||
|
|
||||||
|
export const declaration: CommandDeclaration = {
|
||||||
|
name: 'focusElementToolbar',
|
||||||
|
label: () => _('Toolbar'),
|
||||||
|
parentLabel: () => _('Focus'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const runtime = (dependencies: WindowCommandDependencies): CommandRuntime => {
|
||||||
|
return {
|
||||||
|
execute: async () => {
|
||||||
|
if (!dependencies || !dependencies.containerRef || !dependencies.containerRef.current) return;
|
||||||
|
|
||||||
|
const firstButtonOnRTEToolbar = dependencies.containerRef.current.querySelector(
|
||||||
|
'.tox-toolbar__group button',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (firstButtonOnRTEToolbar) {
|
||||||
|
focus('focusElementToolbar', firstButtonOnRTEToolbar);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstButtonOnMarkdownToolbar = dependencies.containerRef.current.querySelector(
|
||||||
|
'#CodeMirrorToolbar .button:not(.disabled)',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (firstButtonOnMarkdownToolbar) {
|
||||||
|
focus('focusElementToolbar', firstButtonOnMarkdownToolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// AUTO-GENERATED using `gulp buildScriptIndexes`
|
// AUTO-GENERATED using `gulp buildScriptIndexes`
|
||||||
import * as focusElementNoteBody from './focusElementNoteBody';
|
import * as focusElementNoteBody from './focusElementNoteBody';
|
||||||
import * as focusElementNoteTitle from './focusElementNoteTitle';
|
import * as focusElementNoteTitle from './focusElementNoteTitle';
|
||||||
|
import * as focusElementToolbar from './focusElementToolbar';
|
||||||
import * as pasteAsText from './pasteAsText';
|
import * as pasteAsText from './pasteAsText';
|
||||||
import * as showLocalSearch from './showLocalSearch';
|
import * as showLocalSearch from './showLocalSearch';
|
||||||
import * as showRevisions from './showRevisions';
|
import * as showRevisions from './showRevisions';
|
||||||
@@ -8,6 +9,7 @@ import * as showRevisions from './showRevisions';
|
|||||||
const index: any[] = [
|
const index: any[] = [
|
||||||
focusElementNoteBody,
|
focusElementNoteBody,
|
||||||
focusElementNoteTitle,
|
focusElementNoteTitle,
|
||||||
|
focusElementToolbar,
|
||||||
pasteAsText,
|
pasteAsText,
|
||||||
showLocalSearch,
|
showLocalSearch,
|
||||||
showRevisions,
|
showRevisions,
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { ParseOptions } from '@joplin/lib/HtmlToMd';
|
|||||||
import { ScrollStrategy } from '@joplin/editor/CodeMirror/CodeMirrorControl';
|
import { ScrollStrategy } from '@joplin/editor/CodeMirror/CodeMirrorControl';
|
||||||
import { MarkupToHtmlOptions } from '../../hooks/useMarkupToHtml';
|
import { MarkupToHtmlOptions } from '../../hooks/useMarkupToHtml';
|
||||||
import { ScrollbarSize } from '@joplin/lib/models/settings/builtInMetadata';
|
import { ScrollbarSize } from '@joplin/lib/models/settings/builtInMetadata';
|
||||||
|
import { RefObject, SetStateAction } from 'react';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
export interface AllAssetsOptions {
|
export interface AllAssetsOptions {
|
||||||
contentMaxWidthTarget?: string;
|
contentMaxWidthTarget?: string;
|
||||||
@@ -272,3 +274,11 @@ export interface ScrollToTextValue {
|
|||||||
element: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'strong' | 'ul';
|
element: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'strong' | 'ul';
|
||||||
scrollStrategy?: ScrollStrategy;
|
scrollStrategy?: ScrollStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WindowCommandDependencies {
|
||||||
|
setShowLocalSearch: React.Dispatch<SetStateAction<boolean>>;
|
||||||
|
noteSearchBarRef: RefObject<HTMLInputElement>;
|
||||||
|
editorRef: RefObject<NoteBodyEditorRef>;
|
||||||
|
titleInputRef: RefObject<HTMLInputElement>;
|
||||||
|
containerRef: RefObject<HTMLDivElement|null>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { RefObject, useEffect } from 'react';
|
import { RefObject, Dispatch, SetStateAction, useEffect } from 'react';
|
||||||
import { NoteBodyEditorRef, OnChangeEvent, ScrollOptionTypes } from './types';
|
import { WindowCommandDependencies, NoteBodyEditorRef, OnChangeEvent, ScrollOptionTypes } from './types';
|
||||||
import editorCommandDeclarations, { enabledCondition } from '../editorCommandDeclarations';
|
import editorCommandDeclarations, { enabledCondition } from '../editorCommandDeclarations';
|
||||||
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext, RegisteredRuntime } from '@joplin/lib/services/CommandService';
|
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext, RegisteredRuntime } from '@joplin/lib/services/CommandService';
|
||||||
import time from '@joplin/lib/time';
|
import time from '@joplin/lib/time';
|
||||||
@@ -10,14 +10,14 @@ const commandsWithDependencies = [
|
|||||||
require('../commands/showLocalSearch'),
|
require('../commands/showLocalSearch'),
|
||||||
require('../commands/focusElementNoteTitle'),
|
require('../commands/focusElementNoteTitle'),
|
||||||
require('../commands/focusElementNoteBody'),
|
require('../commands/focusElementNoteBody'),
|
||||||
|
require('../commands/focusElementToolbar'),
|
||||||
require('../commands/pasteAsText'),
|
require('../commands/pasteAsText'),
|
||||||
];
|
];
|
||||||
|
|
||||||
type OnBodyChange = (event: OnChangeEvent)=> void;
|
type OnBodyChange = (event: OnChangeEvent)=> void;
|
||||||
|
|
||||||
interface HookDependencies {
|
interface HookDependencies {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
setShowLocalSearch: Dispatch<SetStateAction<boolean>>;
|
||||||
setShowLocalSearch: Function;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||||
dispatch: Function;
|
dispatch: Function;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
@@ -93,11 +93,12 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
const dependencies = {
|
const dependencies: WindowCommandDependencies = {
|
||||||
editorRef,
|
editorRef,
|
||||||
setShowLocalSearch,
|
setShowLocalSearch,
|
||||||
noteSearchBarRef,
|
noteSearchBarRef,
|
||||||
titleInputRef,
|
titleInputRef,
|
||||||
|
containerRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const command of commandsWithDependencies) {
|
for (const command of commandsWithDependencies) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface Props {
|
|||||||
items: ToolbarItem[];
|
items: ToolbarItem[];
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
'aria-label': string;
|
'aria-label': string;
|
||||||
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItemType = (item: ToolbarItem) => {
|
const getItemType = (item: ToolbarItem) => {
|
||||||
@@ -181,6 +182,7 @@ const ToolbarBaseComponent: React.FC<Props> = props => {
|
|||||||
className={`editor-toolbar ${props.scrollable ? '-scrollable' : ''}`}
|
className={`editor-toolbar ${props.scrollable ? '-scrollable' : ''}`}
|
||||||
style={props.style}
|
style={props.style}
|
||||||
|
|
||||||
|
id={props.id ?? undefined}
|
||||||
role='toolbar'
|
role='toolbar'
|
||||||
aria-label={props['aria-label']}
|
aria-label={props['aria-label']}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export default function() {
|
|||||||
'focusElementNoteList',
|
'focusElementNoteList',
|
||||||
'focusElementNoteTitle',
|
'focusElementNoteTitle',
|
||||||
'focusElementSideBar',
|
'focusElementSideBar',
|
||||||
|
'focusElementToolbar',
|
||||||
'focusSearch',
|
'focusSearch',
|
||||||
'historyBackward',
|
'historyBackward',
|
||||||
'historyForward',
|
'historyForward',
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ const defaultKeymapItems = {
|
|||||||
{ accelerator: 'Shift+Cmd+L', command: 'focusElementNoteList' },
|
{ accelerator: 'Shift+Cmd+L', command: 'focusElementNoteList' },
|
||||||
{ accelerator: 'Shift+Cmd+N', command: 'focusElementNoteTitle' },
|
{ accelerator: 'Shift+Cmd+N', command: 'focusElementNoteTitle' },
|
||||||
{ accelerator: 'Shift+Cmd+B', command: 'focusElementNoteBody' },
|
{ accelerator: 'Shift+Cmd+B', command: 'focusElementNoteBody' },
|
||||||
|
{ accelerator: 'Shift+Cmd+O', command: 'focusElementToolbar' },
|
||||||
{ accelerator: 'Option+Cmd+S', command: 'toggleSideBar' },
|
{ accelerator: 'Option+Cmd+S', command: 'toggleSideBar' },
|
||||||
{ accelerator: 'Option+Cmd+L', command: 'toggleNoteList' },
|
{ accelerator: 'Option+Cmd+L', command: 'toggleNoteList' },
|
||||||
{ accelerator: 'Cmd+L', command: 'toggleVisiblePanes' },
|
{ accelerator: 'Cmd+L', command: 'toggleVisiblePanes' },
|
||||||
@@ -86,6 +87,7 @@ const defaultKeymapItems = {
|
|||||||
{ accelerator: 'Ctrl+Shift+L', command: 'focusElementNoteList' },
|
{ accelerator: 'Ctrl+Shift+L', command: 'focusElementNoteList' },
|
||||||
{ accelerator: 'Ctrl+Shift+N', command: 'focusElementNoteTitle' },
|
{ accelerator: 'Ctrl+Shift+N', command: 'focusElementNoteTitle' },
|
||||||
{ accelerator: 'Ctrl+Shift+B', command: 'focusElementNoteBody' },
|
{ accelerator: 'Ctrl+Shift+B', command: 'focusElementNoteBody' },
|
||||||
|
{ accelerator: 'Ctrl+Shift+O', command: 'focusElementToolbar' },
|
||||||
{ accelerator: 'F10', command: 'toggleSideBar' },
|
{ accelerator: 'F10', command: 'toggleSideBar' },
|
||||||
{ accelerator: 'Ctrl+Shift+M', command: 'toggleMenuBar' },
|
{ accelerator: 'Ctrl+Shift+M', command: 'toggleMenuBar' },
|
||||||
{ accelerator: 'F11', command: 'toggleNoteList' },
|
{ accelerator: 'F11', command: 'toggleNoteList' },
|
||||||
|
|||||||
Reference in New Issue
Block a user