-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathFocusTrap.js
More file actions
68 lines (57 loc) · 2.24 KB
/
Copy pathFocusTrap.js
File metadata and controls
68 lines (57 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { Extension } from '@tiptap/core'
let ownPaused = false
const checkHasExtension = (editor, extensionName) => {
return editor.extensionManager.extensions.some(
(extension) => extension.name === extensionName,
)
}
const checkHasListExtension = (editor) => {
return (
checkHasExtension(editor, 'bulletList')
|| checkHasExtension(editor, 'orderedList')
|| checkHasExtension(editor, 'taskList')
)
}
const toggleFocusTrap = ({ editor }) => {
const trapStack = window._nc_focus_trap ?? []
const activeTrap = trapStack[trapStack.length - 1]
const possibleEditorTabCommand
= (checkHasListExtension(editor) && editor.can().sinkListItem('listItem'))
|| (checkHasExtension(editor, 'table') && editor.can().goToNextCell())
|| (checkHasExtension(editor, 'table') && editor.can().goToPreviousCell())
|| (checkHasExtension(editor, 'codeBlock') && editor.isActive('codeBlock'))
if (possibleEditorTabCommand) {
activeTrap?.pause()
ownPaused = true
} else {
if (ownPaused) {
ownPaused = false
activeTrap?.unpause()
}
}
}
const unpauseFocusTrap = ({ editor }) => {
const trapStack = window._nc_focus_trap ?? []
const activeTrap = trapStack[trapStack.length - 1]
activeTrap?.unpause()
}
/**
* The viewer focus trap needs to be paused on the fly in order to properly handle tab commands in the editor,
* as we have no control over if a tab key event is reaching the editor otherwise. This is because the focus trap
* registeres a capture listener (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#capture), so whenever we reach a tab command in the editor the focus trap will already have captured the event.
*
* We also cannot work around this by pushing our own focus trap to the stack, as the focus trap package does not offer any reliable way to programmatically focus the next element of the parent trap if we allow tabbing out of the editor.
*/
const FocusTrap = Extension.create({
name: 'focustrap',
onFocus: toggleFocusTrap,
onBlur: unpauseFocusTrap,
onSelectionUpdate: toggleFocusTrap,
onTransaction: toggleFocusTrap,
onUpdate: toggleFocusTrap,
})
export default FocusTrap