Fix keyboard shortcuts bugs (#2936)
This PR moves the focus ### Change Type - [x] `minor` ### Test Plan 1. Select an element. 2. Press the delete quick action menu button. 3. Undo the delete with a keyboard shortcut. 1. Create a geo shape 2. Use the style panel to change the geo type 3. Undo so that it deletes 4. Try to redo ### Release Notes - [Fix] Keyboard shortcut focus bug --------- Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
This commit is contained in:
parent
fcf97958e8
commit
37bd92ef60
5 changed files with 67 additions and 3 deletions
|
@ -0,0 +1,44 @@
|
||||||
|
import { Editor, Tldraw } from '@tldraw/tldraw'
|
||||||
|
import '@tldraw/tldraw/tldraw.css'
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
export default function EditorFocusExample() {
|
||||||
|
const [focused, setFocused] = useState(false)
|
||||||
|
const rEditorRef = useRef<Editor | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const editor = rEditorRef.current
|
||||||
|
if (!editor) return
|
||||||
|
editor.updateInstanceState({ isFocused: focused })
|
||||||
|
}, [focused])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ padding: 32 }}>
|
||||||
|
<div style={{ display: 'flex', gap: 4 }}>
|
||||||
|
<input
|
||||||
|
id={'focus'}
|
||||||
|
type={'checkbox'}
|
||||||
|
onChange={(e) => {
|
||||||
|
setFocused(e.target.checked)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label htmlFor={'focus'}>Focus</label>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
The checkbox controls the editor's <code>instanceState.isFocused</code> property.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When the editor is "focused", its keyboard shortcuts will work. When it is not focused, the
|
||||||
|
keyboard shortcuts will not work.
|
||||||
|
</p>
|
||||||
|
<div style={{ width: 800, maxWidth: '100%', height: 500 }}>
|
||||||
|
<Tldraw
|
||||||
|
autoFocus={false}
|
||||||
|
onMount={(editor) => {
|
||||||
|
rEditorRef.current = editor
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
18
apps/examples/src/examples/editor-focus/README.md
Normal file
18
apps/examples/src/examples/editor-focus/README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
title: Editor focus
|
||||||
|
component: ./EditorFocusExample.tsx
|
||||||
|
category: basic
|
||||||
|
priority: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
The editor's keyboard shortcuts only work when the editor is "focused".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
In this example, we drive the editor's focus in order to turn on and off keyboard shortcuts.
|
||||||
|
|
||||||
|
The editor's focus is different from—but usually corresponds to—the browser's concept of "focus", which is related to the document's [active element](https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement).
|
||||||
|
|
||||||
|
Unfortunately, the browser's focus cannot be relied on to determine whether the editor's keyboard shortcuts should work. While its possible to detect whether the document's active element is a descendant of the Tldraw component's own element, it's not 100% reliable. For example, iframes are not considered descendants of their parents, and many menus are portalled into different parts of the document tree.
|
||||||
|
|
||||||
|
For these reasons, the responsibility falls to you, dear developer, to manage focus for your Tldraw editor, especially in cases where there are more than one editor on the same page.
|
|
@ -31,6 +31,8 @@ export default function MultipleExample() {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
padding: 32,
|
padding: 32,
|
||||||
}}
|
}}
|
||||||
|
// Sorry you need to do this yourself
|
||||||
|
onPointerDown={() => setFocusedEditor(null)}
|
||||||
>
|
>
|
||||||
<focusedEditorContext.Provider value={{ focusedEditor, setFocusedEditor }}>
|
<focusedEditorContext.Provider value={{ focusedEditor, setFocusedEditor }}>
|
||||||
<h1>Focusing: {focusedEditor ?? 'none'}</h1>
|
<h1>Focusing: {focusedEditor ?? 'none'}</h1>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
title: Multiple editors
|
title: Multiple editors
|
||||||
component: ./MultipleExample.tsx
|
component: ./MultipleExample.tsx
|
||||||
category: basic
|
category: basic
|
||||||
priority: 7
|
priority: 8
|
||||||
---
|
---
|
||||||
|
|
||||||
Use multiple `<Tldraw/>` components on the same page.
|
Use multiple `<Tldraw/>` components on the same page.
|
||||||
|
|
|
@ -33,13 +33,13 @@ export function useKeyboardShortcuts() {
|
||||||
hotkeys.setScope(editor.store.id)
|
hotkeys.setScope(editor.store.id)
|
||||||
|
|
||||||
const hot = (keys: string, callback: (event: KeyboardEvent) => void) => {
|
const hot = (keys: string, callback: (event: KeyboardEvent) => void) => {
|
||||||
hotkeys(keys, { element: container, scope: editor.store.id }, callback)
|
hotkeys(keys, { element: document.body, scope: editor.store.id }, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
const hotUp = (keys: string, callback: (event: KeyboardEvent) => void) => {
|
const hotUp = (keys: string, callback: (event: KeyboardEvent) => void) => {
|
||||||
hotkeys(
|
hotkeys(
|
||||||
keys,
|
keys,
|
||||||
{ element: container, keyup: true, keydown: false, scope: editor.store.id },
|
{ element: document.body, keyup: true, keydown: false, scope: editor.store.id },
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue