[web] Ensure buttons and links have discernible text on the editor page (#25005)

* Use OLIconButton for buttons lacking visible text

* Ensure correct ARIA attr for the Layout dropdown

* Add a tooltip to Layout button

* Add "Open dev tool" aria-label

* Add accessible names to the rail tab items

* Remove unused IconProps export

GitOrigin-RevId: 185937384cf5ec87b32238111d6621ac07789fb4
This commit is contained in:
Rebeka Dekany
2025-04-24 13:07:38 +02:00
committed by Copybot
parent 21acae4463
commit ae12b4a356
7 changed files with 105 additions and 58 deletions

View File

@@ -1,4 +1,5 @@
import { FC, ReactElement, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Nav, NavLink, Tab, TabContainer } from 'react-bootstrap-5'
import MaterialIcon, {
AvailableUnfilledIcon,
@@ -16,10 +17,8 @@ import { ChatIndicator, ChatPane } from './chat/chat'
import getMeta from '@/utils/meta'
import { HorizontalResizeHandle } from '@/features/ide-react/components/resize/horizontal-resize-handle'
import { HorizontalToggler } from '@/features/ide-react/components/resize/horizontal-toggler'
import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
import IntegrationsPanel from './integrations-panel/integrations-panel'
import OLButton from '@/features/ui/components/ol/ol-button'
import {
Dropdown,
DropdownDivider,
@@ -32,6 +31,7 @@ import { RailHelpContactUsModal } from './help/contact-us'
import { HistorySidebar } from '@/features/ide-react/components/history-sidebar'
import DictionarySettingsModal from './settings/editor-settings/dictionary-settings-modal'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
type RailElement = {
icon: AvailableUnfilledIcon
@@ -277,11 +277,16 @@ const RailTab = ({
})}
>
{open ? (
<MaterialIcon className="ide-rail-tab-link-icon" type={icon} />
<MaterialIcon
className="ide-rail-tab-link-icon"
type={icon}
accessibilityLabel={title}
/>
) : (
<MaterialIcon
className="ide-rail-tab-link-icon"
type={icon}
accessibilityLabel={title}
unfilled
/>
)}
@@ -292,13 +297,6 @@ const RailTab = ({
}
const RailActionElement = ({ action }: { action: RailAction }) => {
const icon = (
<MaterialIcon
className="ide-rail-tab-link-icon"
type={action.icon}
unfilled
/>
)
const onActionClick = useCallback(() => {
if ('action' in action) {
action.action()
@@ -318,8 +316,13 @@ const RailActionElement = ({ action }: { action: RailAction }) => {
id="rail-help-dropdown-btn"
className="ide-rail-tab-link ide-rail-tab-button ide-rail-tab-dropdown"
as="button"
aria-label={action.title}
>
{icon}
<MaterialIcon
className="ide-rail-tab-link-icon"
type={action.icon}
unfilled
/>
</DropdownToggle>
</span>
</OLTooltip>
@@ -333,30 +336,31 @@ const RailActionElement = ({ action }: { action: RailAction }) => {
description={action.title}
overlayProps={{ delay: 0, placement: 'right' }}
>
<button
<OLIconButton
onClick={onActionClick}
className="ide-rail-tab-link ide-rail-tab-button"
type="button"
>
{icon}
</button>
icon={action.icon}
accessibilityLabel={action.title}
unfilled
/>
</OLTooltip>
)
}
}
export const RailPanelHeader: FC<{ title: string }> = ({ title }) => {
const { t } = useTranslation()
const { handlePaneCollapse } = useRailContext()
return (
<header className="rail-panel-header">
<h4 className="rail-panel-title">{title}</h4>
<OLButton
<OLIconButton
onClick={handlePaneCollapse}
className="rail-panel-header-button-subdued"
icon="close"
accessibilityLabel={t('close')}
size="sm"
>
<MaterialIcon type="close" />
</OLButton>
/>
</header>
)
}

View File

@@ -1,41 +1,40 @@
import OLButton from '@/features/ui/components/ol/ol-button'
import MaterialIcon from '@/shared/components/material-icon'
import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
import {
Dropdown,
DropdownMenu,
DropdownToggle,
} from '@/features/ui/components/bootstrap-5/dropdown-menu'
import React, { forwardRef } from 'react'
import ChangeLayoutOptions from './change-layout-options'
const LayoutDropdownToggleButton = forwardRef<
HTMLButtonElement,
{
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
}
>(({ onClick }, ref) => {
return (
<OLButton
size="sm"
className="ide-redesign-toolbar-button-subdued"
ref={ref}
onClick={onClick}
leadingIcon={<MaterialIcon unfilled type="space_dashboard" />}
/>
)
})
LayoutDropdownToggleButton.displayName = 'LayoutDropdownToggleButton'
import MaterialIcon from '@/shared/components/material-icon'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
export default function ChangeLayoutButton() {
const { t } = useTranslation()
const toggleButtonClassName = classNames(
'ide-redesign-toolbar-button-subdued',
'ide-redesign-toolbar-dropdown-toggle-subdued',
'ide-redesign-toolbar-button-icon'
)
return (
<div className="ide-redesign-toolbar-button-container">
<Dropdown className="toolbar-item layout-dropdown" align="end">
<DropdownToggle
id="layout-dropdown-btn"
className="btn-full-height"
as={LayoutDropdownToggleButton}
/>
<OLTooltip
id="tooltip-open-layout-options"
description={t('layout_options')}
overlayProps={{ delay: 0, placement: 'bottom' }}
>
<span>
<DropdownToggle
id="layout-dropdown-btn"
className={toggleButtonClassName}
aria-label={t('layout_options')}
>
<MaterialIcon type="space_dashboard" unfilled />
</DropdownToggle>
</span>
</OLTooltip>
<DropdownMenu>
<ChangeLayoutOptions />
</DropdownMenu>

View File

@@ -1,10 +1,9 @@
import OLButton from '@/features/ui/components/ol/ol-button'
import MaterialIcon from '@/shared/components/material-icon'
import { useTranslation } from 'react-i18next'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import * as eventTracking from '../../../../infrastructure/event-tracking'
import { useLayoutContext } from '@/shared/context/layout-context'
import { useCallback } from 'react'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
export default function ShowHistoryButton() {
const { t } = useTranslation()
@@ -24,12 +23,11 @@ export default function ShowHistoryButton() {
description={t('history')}
overlayProps={{ delay: 0, placement: 'bottom' }}
>
<OLButton
size="sm"
variant="ghost"
className="ide-redesign-toolbar-button-subdued"
leadingIcon={<MaterialIcon type="history" />}
<OLIconButton
icon="history"
className="ide-redesign-toolbar-button-subdued ide-redesign-toolbar-button-icon"
onClick={toggleHistoryOpen}
accessibilityLabel={t('history')}
/>
</OLTooltip>
</div>

View File

@@ -6,7 +6,15 @@ import type { IconButtonProps } from '@/features/ui/components/types/icon-button
const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
(
{ accessibilityLabel, icon, isLoading = false, size, className, ...props },
{
accessibilityLabel,
icon,
isLoading = false,
size,
className,
unfilled,
...props
},
ref
) => {
const iconButtonClassName = classNames(className, {
@@ -17,6 +25,7 @@ const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
const iconSizeClassName = size === 'lg' ? 'icon-large' : 'icon-small'
const materialIconClassName = classNames(iconSizeClassName, {
'button-content-hidden': isLoading,
unfilled,
})
return (

View File

@@ -1,7 +1,19 @@
import { AvailableUnfilledIcon } from '@/shared/components/material-icon'
import { ButtonProps } from './button-props'
export type IconButtonProps = ButtonProps & {
type BaseIconButtonProps = ButtonProps & {
accessibilityLabel?: string
icon: string
type?: 'button' | 'submit'
}
type FilledIconButtonProps = BaseIconButtonProps & {
icon: string
unfilled?: false
}
type UnfilledIconButtonProps = BaseIconButtonProps & {
icon: AvailableUnfilledIcon
unfilled: true
}
export type IconButtonProps = FilledIconButtonProps | UnfilledIconButtonProps

View File

@@ -72,6 +72,10 @@
color: var(--ide-rail-color);
}
&:focus-visible {
background-color: transparent;
}
&:hover {
color: var(--ide-rail-link-hover-color);
background-color: var(--ide-rail-link-hover-background);

View File

@@ -59,6 +59,27 @@
);
text-decoration: none;
&.ide-redesign-toolbar-button-icon {
@include ol-button-variant(
var(--redesign-subdued-button-color),
var(--redesign-toolbar-background),
transparent,
var(--redesign-subdued-button-hover-background),
transparent,
true
);
border-radius: var(--border-radius-full);
display: flex;
justify-content: center;
padding: var(--spacing-02);
&:visited,
&:focus {
color: var(--redesign-subdued-button-color);
}
}
}
.ide-redesign-toolbar-home-link {