add aria-labels to elements for screen readers (#1106)
This commit is contained in:
parent
60728e069a
commit
6f87ff022a
6 changed files with 136 additions and 24 deletions
|
@ -89,6 +89,7 @@ export function ToolButtonWithTooltip({
|
|||
isToolLocked={isLocked && rest.isActive}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
aria-label={label[0].toUpperCase() + label.slice(1)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
|
|
|
@ -189,7 +189,7 @@ export function ActionButton() {
|
|||
return (
|
||||
<DropdownMenu.Root dir="ltr" onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild id="TD-Tools-Dots">
|
||||
<ToolButton variant="circle">
|
||||
<ToolButton aria-label={intl.formatMessage({ id: 'shape.options' })} variant="circle">
|
||||
<DotsHorizontalIcon />
|
||||
</ToolButton>
|
||||
</DropdownMenu.Trigger>
|
||||
|
@ -197,12 +197,20 @@ export function ActionButton() {
|
|||
<>
|
||||
<ButtonsRow>
|
||||
<Tooltip label={intl.formatMessage({ id: 'duplicate' })} kbd={`#D`} id="TD-Tools-Copy">
|
||||
<ToolButton disabled={!hasSelection} onClick={handleDuplicate}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'duplicate' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleDuplicate}
|
||||
>
|
||||
<CopyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'rotate' })} id="TD-Tools-Rotate">
|
||||
<ToolButton disabled={!hasSelection} onClick={handleRotate}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'rotate' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleRotate}
|
||||
>
|
||||
<RotateCounterClockwiseIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -211,7 +219,11 @@ export function ActionButton() {
|
|||
kbd={`#L`}
|
||||
id="TD-Tools-Lock"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleToggleLocked}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: isAllLocked ? 'unlock' : 'lock' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleToggleLocked}
|
||||
>
|
||||
{isAllLocked ? <LockClosedIcon /> : <LockOpen1Icon />}
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -221,12 +233,19 @@ export function ActionButton() {
|
|||
})}
|
||||
id="TD-Tools-AspectRatio"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleToggleAspectRatio}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({
|
||||
id: isAllAspectLocked ? 'unlock.aspect.ratio' : 'lock.aspect.ratio',
|
||||
})}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleToggleAspectRatio}
|
||||
>
|
||||
{isAllAspectLocked ? <AspectRatioIcon /> : <BoxIcon />}
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'group' })} kbd={`#G`} id="TD-Tools-Group">
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'group' })}
|
||||
disabled={!hasSelection || (!isAllGrouped && !hasMultipleSelection)}
|
||||
onClick={handleGroup}
|
||||
>
|
||||
|
@ -240,7 +259,11 @@ export function ActionButton() {
|
|||
kbd={`#⇧[`}
|
||||
id="TD-Tools-PinBottom"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveToBack}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'move.to.back' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleMoveToBack}
|
||||
>
|
||||
<PinBottomIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -249,7 +272,11 @@ export function ActionButton() {
|
|||
kbd={`#[`}
|
||||
id="TD-Tools-ArrowDown"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveBackward}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'move.backward' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleMoveBackward}
|
||||
>
|
||||
<ArrowDownIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -258,7 +285,11 @@ export function ActionButton() {
|
|||
kbd={`#]`}
|
||||
id="TD-Tools-ArrowUp"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveForward}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'move.forward' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleMoveForward}
|
||||
>
|
||||
<ArrowUpIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -267,12 +298,20 @@ export function ActionButton() {
|
|||
kbd={`#⇧]`}
|
||||
id="TD-Tools-PinTop"
|
||||
>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveToFront}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'move.to.front' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleMoveToFront}
|
||||
>
|
||||
<PinTopIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'reset.angle' })} id="TD-Tools-ResetAngle">
|
||||
<ToolButton disabled={!hasSelection} onClick={handleResetAngle}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'reset.angle' })}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleResetAngle}
|
||||
>
|
||||
<AngleIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -280,7 +319,11 @@ export function ActionButton() {
|
|||
<Divider />
|
||||
<ButtonsRow>
|
||||
<Tooltip label={intl.formatMessage({ id: 'align.left' })} id="TD-Tools-AlignLeft">
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignLeft}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.left' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignLeft}
|
||||
>
|
||||
<AlignLeftIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -288,12 +331,20 @@ export function ActionButton() {
|
|||
label={intl.formatMessage({ id: 'align.center.x' })}
|
||||
id="TD-Tools-AlignCenterHorizontal"
|
||||
>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignCenterHorizontal}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.center.x' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignCenterHorizontal}
|
||||
>
|
||||
<AlignCenterHorizontallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'align.right' })} id="TD-Tools-AlignRight">
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignRight}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.right' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignRight}
|
||||
>
|
||||
<AlignRightIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -301,7 +352,11 @@ export function ActionButton() {
|
|||
label={intl.formatMessage({ id: 'stretch.x' })}
|
||||
id="TD-Tools-StretchHorizontal"
|
||||
>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={stretchHorizontally}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'stretch.x' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={stretchHorizontally}
|
||||
>
|
||||
<StretchHorizontallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -309,14 +364,22 @@ export function ActionButton() {
|
|||
label={intl.formatMessage({ id: 'distribute.x' })}
|
||||
id="TD-Tools-SpaceEvenlyHorizontal"
|
||||
>
|
||||
<ToolButton disabled={!hasThreeOrMore} onClick={distributeHorizontally}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'distribute.x' })}
|
||||
disabled={!hasThreeOrMore}
|
||||
onClick={distributeHorizontally}
|
||||
>
|
||||
<SpaceEvenlyHorizontallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
</ButtonsRow>
|
||||
<ButtonsRow>
|
||||
<Tooltip label={intl.formatMessage({ id: 'align.top' })} id="TD-Tools-AlignTop">
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignTop}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.top' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignTop}
|
||||
>
|
||||
<AlignTopIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -324,17 +387,29 @@ export function ActionButton() {
|
|||
label={intl.formatMessage({ id: 'align.center.y' })}
|
||||
id="TD-Tools-AlignCenterVertical"
|
||||
>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignCenterVertical}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.center.y' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignCenterVertical}
|
||||
>
|
||||
<AlignCenterVerticallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'align.bottom' })} id="TD-Tools-AlignBottom">
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignBottom}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'align.bottom' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignBottom}
|
||||
>
|
||||
<AlignBottomIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
<Tooltip label={intl.formatMessage({ id: 'stretch.y' })} id="TD-Tools-StretchVertical">
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={stretchVertically}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'stretch.y' })}
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={stretchVertically}
|
||||
>
|
||||
<StretchVerticallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
@ -342,7 +417,11 @@ export function ActionButton() {
|
|||
label={intl.formatMessage({ id: 'distribute.y' })}
|
||||
id="TD-Tools-SpaceEvenlyVertical"
|
||||
>
|
||||
<ToolButton disabled={!hasThreeOrMore} onClick={distributeVertically}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'distribute.y' })}
|
||||
disabled={!hasThreeOrMore}
|
||||
onClick={distributeVertically}
|
||||
>
|
||||
<SpaceEvenlyVerticallyIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
|
|
@ -21,7 +21,12 @@ export function DeleteButton() {
|
|||
|
||||
return (
|
||||
<Tooltip label={intl.formatMessage({ id: 'delete' })} kbd="⌫" id="TD-Delete">
|
||||
<ToolButton variant="circle" disabled={!hasSelection} onSelect={handleDelete}>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: 'delete' })}
|
||||
variant="circle"
|
||||
disabled={!hasSelection}
|
||||
onSelect={handleDelete}
|
||||
>
|
||||
<TrashIcon />
|
||||
</ToolButton>
|
||||
</Tooltip>
|
||||
|
|
|
@ -84,6 +84,7 @@ export const ShapesMenu = React.memo(function ShapesMenu({
|
|||
isToolLocked={isActive && isToolLocked}
|
||||
isActive={isActive}
|
||||
onKeyDown={handleKeyDown}
|
||||
aria-label={intl.formatMessage({ id: 'shapes' })}
|
||||
>
|
||||
{shapeShapeIcons[lastActiveTool]}
|
||||
</ToolButton>
|
||||
|
@ -99,6 +100,7 @@ export const ShapesMenu = React.memo(function ShapesMenu({
|
|||
>
|
||||
<DropdownMenu.Item asChild>
|
||||
<ToolButton
|
||||
aria-label={intl.formatMessage({ id: shape })}
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
app.selectTool(shape)
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
TextAlignRightIcon,
|
||||
} from '@radix-ui/react-icons'
|
||||
import * as React from 'react'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
import { Divider } from '~components/Primitives/Divider'
|
||||
import { DMCheckboxItem, DMContent, DMRadioItem } from '~components/Primitives/DropdownMenu'
|
||||
import { ToolButton } from '~components/Primitives/ToolButton'
|
||||
|
@ -105,6 +105,8 @@ const optionsSelector = (s: TDSnapshot) => {
|
|||
export const StyleMenu = React.memo(function ColorMenu() {
|
||||
const app = useTldrawApp()
|
||||
|
||||
const intl = useIntl()
|
||||
|
||||
const theme = app.useStore(themeSelector)
|
||||
|
||||
const keepOpen = app.useStore(keepOpenSelector)
|
||||
|
@ -194,7 +196,7 @@ export const StyleMenu = React.memo(function ColorMenu() {
|
|||
modal={false}
|
||||
>
|
||||
<DropdownMenu.Trigger asChild id="TD-Styles">
|
||||
<ToolButton variant="text">
|
||||
<ToolButton aria-label={intl.formatMessage({ id: 'styles' })} variant="text">
|
||||
<FormattedMessage id="styles" />
|
||||
<OverlapIcons
|
||||
style={{
|
||||
|
@ -229,6 +231,7 @@ export const StyleMenu = React.memo(function ColorMenu() {
|
|||
variant="icon"
|
||||
isActive={displayedStyle.color === style}
|
||||
onClick={() => app.style({ color: style as ColorStyle })}
|
||||
aria-label={intl.formatMessage({ id: style })}
|
||||
>
|
||||
<CircleIcon
|
||||
size={18}
|
||||
|
@ -262,6 +265,7 @@ export const StyleMenu = React.memo(function ColorMenu() {
|
|||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Dash-${style}`}
|
||||
aria-label={intl.formatMessage({ id: style })}
|
||||
>
|
||||
{DASH_ICONS[style as DashStyle]}
|
||||
</DMRadioItem>
|
||||
|
@ -279,6 +283,7 @@ export const StyleMenu = React.memo(function ColorMenu() {
|
|||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Dash-${sizeStyle}`}
|
||||
aria-label={intl.formatMessage({ id: sizeStyle })}
|
||||
>
|
||||
{SIZE_ICONS[sizeStyle as SizeStyle]}
|
||||
</DMRadioItem>
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
"new.page": "New Page",
|
||||
"page.name": "Page Name",
|
||||
"duplicate": "Duplicate",
|
||||
"shape.options": "Shape Options",
|
||||
"shapes": "Shapes",
|
||||
"cancel": "Cancel",
|
||||
"copy.invite.link": "Copy Invite Link",
|
||||
"copy.readonly.link": "Copy ReadOnly Link",
|
||||
|
@ -124,5 +126,23 @@
|
|||
"dialog.no": "No",
|
||||
"dialog.yes": "Yes",
|
||||
"enter.file.name": "Enter file name",
|
||||
"tldraw-beta": "Try the new tldraw"
|
||||
"tldraw-beta": "Try the new tldraw",
|
||||
"white": "White",
|
||||
"lightGray": "Light gray",
|
||||
"gray": "Gray",
|
||||
"black": "Black",
|
||||
"green": "Green",
|
||||
"cyan": "Cyan",
|
||||
"blue": "Blue",
|
||||
"indigo": "Indigo",
|
||||
"violet": "Violet",
|
||||
"red": "Red",
|
||||
"orange": "Orange",
|
||||
"yellow": "Yellow",
|
||||
"solid": "Solid",
|
||||
"dashed": "Dashed",
|
||||
"dotted": "Dotted",
|
||||
"small": "Small",
|
||||
"medium": "Medium",
|
||||
"large": "Large"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue