mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 22:23:42 +01:00
Merge pull request #30490 from overleaf/mg-context-menu-a11y
[web] Add a11y support for context menu GitOrigin-RevId: 3cbe66ee3ee8345dd0e89f89561928889832a50d
This commit is contained in:
@@ -4,12 +4,13 @@ import {
|
||||
} from '@/features/source-editor/components/codemirror-context'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import useSynctex from '@/features/pdf-preview/hooks/use-synctex'
|
||||
import { useDetachCompileContext } from '@/shared/context/detach-compile-context'
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import {
|
||||
formatShortcut,
|
||||
useCommandRegistry,
|
||||
@@ -35,20 +36,33 @@ export const useContextMenuItems = () => {
|
||||
const visualPreviewEnabled = useFeatureFlag('visual-preview')
|
||||
const { t } = useTranslation()
|
||||
const { shortcuts } = useCommandRegistry()
|
||||
const { features } = useProjectContext()
|
||||
const requestedPdfSyncRef = useRef(false)
|
||||
|
||||
const closeMenu = useCallback(() => {
|
||||
view.dispatch({ effects: closeContextMenuEffect.of(null) })
|
||||
}, [view])
|
||||
|
||||
const [pendingClose, setPendingClose] = useState(false)
|
||||
// Handle closing the menu when it loses focus, e.g. click outside the editor
|
||||
const onToggle = (show: boolean) => {
|
||||
if (!show) {
|
||||
// Skip closing if a sync to PDF is in flight
|
||||
if (requestedPdfSyncRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for syncToPdf to finish before closing the menu
|
||||
useEffect(() => {
|
||||
if (pendingClose && !syncToPdfInFlight) {
|
||||
if (requestedPdfSyncRef.current && !syncToPdfInFlight) {
|
||||
closeMenu()
|
||||
setPendingClose(false)
|
||||
// Clear the synchronous flag when the close completes
|
||||
requestedPdfSyncRef.current = false
|
||||
}
|
||||
}, [pendingClose, syncToPdfInFlight, closeMenu])
|
||||
}, [syncToPdfInFlight, closeMenu])
|
||||
|
||||
const hasSelection = !state.selection.main.empty
|
||||
const canEdit = permissions.write || permissions.trackedWrite
|
||||
@@ -94,8 +108,8 @@ export const useContextMenuItems = () => {
|
||||
|
||||
// Sync-to-PDF is special: it needs to wait for async completion before closing
|
||||
const handleSyncToPdf = useCallback(() => {
|
||||
requestedPdfSyncRef.current = true
|
||||
syncToPdf()
|
||||
setPendingClose(true)
|
||||
view.focus()
|
||||
}, [syncToPdf, view])
|
||||
|
||||
@@ -107,66 +121,71 @@ export const useContextMenuItems = () => {
|
||||
[shortcuts]
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
label: t('cut'),
|
||||
handler: handleCut,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('cut'),
|
||||
},
|
||||
{
|
||||
label: t('copy'),
|
||||
handler: handleCopy,
|
||||
disabled: false,
|
||||
show: true,
|
||||
shortcut: getShortcut('copy'),
|
||||
},
|
||||
{
|
||||
label: t('paste'),
|
||||
handler: handlePaste,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('paste'),
|
||||
},
|
||||
{
|
||||
label: inVisualMode
|
||||
? t('paste_without_formatting')
|
||||
: t('paste_with_formatting'),
|
||||
handler: handlePasteSpecial,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: inVisualMode ? getShortcut('paste-special') : undefined,
|
||||
},
|
||||
{
|
||||
label: t('delete'),
|
||||
handler: handleDelete,
|
||||
disabled: !hasSelection,
|
||||
show: canEdit,
|
||||
shortcut: undefined,
|
||||
},
|
||||
{
|
||||
label: t('jump_to_location_in_pdf'),
|
||||
handler: handleSyncToPdf,
|
||||
disabled: syncToPdfInFlight,
|
||||
separatorAbove: true,
|
||||
show: jumpToLocationInPdfEnabled,
|
||||
shortcut: undefined,
|
||||
},
|
||||
{
|
||||
label: wantTrackChanges ? t('back_to_editing') : t('suggest_edits'),
|
||||
handler: handleToggleTrackChanges,
|
||||
disabled: false,
|
||||
separatorAbove: true,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('toggle-track-changes'),
|
||||
},
|
||||
{
|
||||
label: t('comment'),
|
||||
handler: handleComment,
|
||||
disabled: !hasSelection,
|
||||
show: permissions.comment,
|
||||
shortcut: getShortcut('insert-comment'),
|
||||
},
|
||||
].filter(item => item.show)
|
||||
return {
|
||||
closeMenu,
|
||||
onToggle,
|
||||
menuItems: [
|
||||
{
|
||||
label: t('cut'),
|
||||
handler: handleCut,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('cut'),
|
||||
},
|
||||
{
|
||||
label: t('copy'),
|
||||
handler: handleCopy,
|
||||
disabled: false,
|
||||
show: true,
|
||||
shortcut: getShortcut('copy'),
|
||||
},
|
||||
{
|
||||
label: t('paste'),
|
||||
handler: handlePaste,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('paste'),
|
||||
},
|
||||
{
|
||||
label: inVisualMode
|
||||
? t('paste_without_formatting')
|
||||
: t('paste_with_formatting'),
|
||||
handler: handlePasteSpecial,
|
||||
disabled: false,
|
||||
show: canEdit,
|
||||
shortcut: inVisualMode ? getShortcut('paste-special') : undefined,
|
||||
},
|
||||
{
|
||||
label: t('delete'),
|
||||
handler: handleDelete,
|
||||
disabled: !hasSelection,
|
||||
show: canEdit,
|
||||
shortcut: undefined,
|
||||
},
|
||||
{
|
||||
label: t('jump_to_location_in_pdf'),
|
||||
handler: handleSyncToPdf,
|
||||
disabled: syncToPdfInFlight,
|
||||
separatorAbove: true,
|
||||
show: jumpToLocationInPdfEnabled,
|
||||
shortcut: undefined,
|
||||
},
|
||||
{
|
||||
label: wantTrackChanges ? t('back_to_editing') : t('suggest_edits'),
|
||||
handler: handleToggleTrackChanges,
|
||||
// disable for now, future work opens upgrade modal
|
||||
disabled: !features.trackChanges,
|
||||
separatorAbove: true,
|
||||
show: canEdit,
|
||||
shortcut: getShortcut('toggle-track-changes'),
|
||||
},
|
||||
{
|
||||
label: t('comment'),
|
||||
handler: handleComment,
|
||||
disabled: !hasSelection,
|
||||
show: permissions.comment,
|
||||
shortcut: getShortcut('insert-comment'),
|
||||
},
|
||||
].filter(item => item.show),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user