Make editor popover toolbar keyboard focusable (#25169)
* Remove redundant class conflicting with focus styling * Make the toolbar in the popover focusable via keyboard * Focus to the first context menu item via keyboard only GitOrigin-RevId: 7d3e2af4ba96654b5b2312b3999483c2a439b406
This commit is contained in:
@@ -21,7 +21,7 @@ export const ToolbarButtonMenu: FC<{
|
||||
const button = (
|
||||
<button
|
||||
type="button"
|
||||
className="ol-cm-toolbar-button btn"
|
||||
className="ol-cm-toolbar-button"
|
||||
aria-label={label}
|
||||
onMouseDown={event => {
|
||||
event.preventDefault()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC, useRef } from 'react'
|
||||
import { FC, useCallback, useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import classnames from 'classnames'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-context'
|
||||
@@ -11,7 +12,10 @@ export const ToolbarOverflow: FC<{
|
||||
setOverflowOpen: (open: boolean) => void
|
||||
overflowRef?: React.Ref<HTMLDivElement>
|
||||
}> = ({ overflowed, overflowOpen, setOverflowOpen, overflowRef, children }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||
const keyboardInputRef = useRef(false)
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
const className = classnames(
|
||||
@@ -22,6 +26,46 @@ export const ToolbarOverflow: FC<{
|
||||
}
|
||||
)
|
||||
|
||||
// A11y - Move the focus inside the popover to the first toolbar button when it opens
|
||||
const handlePopoverFocus = useCallback(() => {
|
||||
if (keyboardInputRef.current) {
|
||||
const firstToolbarItem = document.querySelector(
|
||||
'#popover-toolbar-overflow .ol-cm-toolbar-overflow button:not([disabled])'
|
||||
) as HTMLButtonElement | null
|
||||
|
||||
if (firstToolbarItem) {
|
||||
firstToolbarItem.focus()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleKeyDown = useCallback(() => {
|
||||
keyboardInputRef.current = true
|
||||
}, [])
|
||||
|
||||
const handleMouseDown = useCallback(() => {
|
||||
keyboardInputRef.current = false
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
document.addEventListener('mousedown', handleMouseDown)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
document.removeEventListener('mousedown', handleMouseDown)
|
||||
}
|
||||
}, [handleKeyDown, handleMouseDown])
|
||||
|
||||
// A11y - Move the focus back to the trigger when the popover is dismissed
|
||||
const handleCloseAndReturnFocus = useCallback(() => {
|
||||
setOverflowOpen(false)
|
||||
|
||||
if (keyboardInputRef.current && buttonRef.current) {
|
||||
buttonRef.current.focus()
|
||||
}
|
||||
}, [setOverflowOpen])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@@ -29,7 +73,9 @@ export const ToolbarOverflow: FC<{
|
||||
type="button"
|
||||
id="toolbar-more"
|
||||
className={className}
|
||||
aria-label="More"
|
||||
aria-label={t('more_editor_toolbar_item')}
|
||||
aria-expanded={overflowOpen}
|
||||
aria-controls="popover-toolbar-overflow"
|
||||
onMouseDown={event => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
@@ -49,9 +95,14 @@ export const ToolbarOverflow: FC<{
|
||||
// containerPadding={0}
|
||||
transition
|
||||
rootClose
|
||||
onHide={() => setOverflowOpen(false)}
|
||||
onHide={handleCloseAndReturnFocus}
|
||||
onEntered={handlePopoverFocus}
|
||||
>
|
||||
<OLPopover id="popover-toolbar-overflow" ref={overflowRef}>
|
||||
<OLPopover
|
||||
id="popover-toolbar-overflow"
|
||||
ref={overflowRef}
|
||||
role="toolbar"
|
||||
>
|
||||
<div className="ol-cm-toolbar-overflow">{children}</div>
|
||||
</OLPopover>
|
||||
</OLOverlay>
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ export const LegacyTableDropdown = memo(() => {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="ol-cm-toolbar-button btn"
|
||||
className="ol-cm-toolbar-button"
|
||||
aria-label={t('toolbar_insert_table')}
|
||||
onMouseDown={event => {
|
||||
event.preventDefault()
|
||||
|
||||
Reference in New Issue
Block a user