Add ability to dismiss alt text badge by tapping it in web UI

This commit is contained in:
Eugen Rochko 2025-01-26 13:47:54 +01:00
parent 2df86d6413
commit 9e28b33efc
4 changed files with 80 additions and 4 deletions

View File

@ -0,0 +1,55 @@
import { useRef, useCallback } from 'react';
type Position = [number, number];
export const useSelectableClick = (
onClick: React.MouseEventHandler,
maxDelta = 5,
) => {
const clickPositionRef = useRef<Position | null>(null);
const handleMouseDown = useCallback((e: React.MouseEvent) => {
clickPositionRef.current = [e.clientX, e.clientY];
}, []);
const handleMouseUp = useCallback(
(e: React.MouseEvent) => {
if (!clickPositionRef.current) {
return;
}
const [startX, startY] = clickPositionRef.current;
const [deltaX, deltaY] = [
Math.abs(e.clientX - startX),
Math.abs(e.clientY - startY),
];
let element: EventTarget | null = e.target;
while (element && element instanceof HTMLElement) {
if (
element.localName === 'button' ||
element.localName === 'a' ||
element.localName === 'label'
) {
return;
}
element = element.parentNode;
}
if (
deltaX + deltaY < maxDelta &&
(e.button === 0 || e.button === 1) &&
e.detail >= 1
) {
onClick(e);
}
clickPositionRef.current = null;
},
[maxDelta, onClick],
);
return [handleMouseDown, handleMouseUp] as const;
};

View File

@ -1,4 +1,4 @@
import { useState, useCallback, useRef } from 'react';
import { useState, useCallback, useRef, useId } from 'react';
import { FormattedMessage } from 'react-intl';
@ -8,12 +8,15 @@ import type {
UsePopperOptions,
} from 'react-overlays/esm/usePopper';
import { useSelectableClick } from '@/hooks/useSelectableClick';
const offset = [0, 4] as OffsetValue;
const popperConfig = { strategy: 'fixed' } as UsePopperOptions;
export const AltTextBadge: React.FC<{
description: string;
}> = ({ description }) => {
const accessibilityId = useId();
const anchorRef = useRef<HTMLButtonElement>(null);
const [open, setOpen] = useState(false);
@ -25,12 +28,16 @@ export const AltTextBadge: React.FC<{
setOpen(false);
}, [setOpen]);
const [handleMouseDown, handleMouseUp] = useSelectableClick(handleClose);
return (
<>
<button
ref={anchorRef}
className='media-gallery__alt__label'
onClick={handleClick}
aria-expanded={open}
aria-controls={accessibilityId}
>
ALT
</button>
@ -47,9 +54,12 @@ export const AltTextBadge: React.FC<{
>
{({ props }) => (
<div {...props} className='hover-card-controller'>
<div
<div // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
className='media-gallery__alt__popover dropdown-animation'
role='tooltip'
id={accessibilityId}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
<h4>
<FormattedMessage

View File

@ -1,4 +1,4 @@
import { useState, useRef, useCallback } from 'react';
import { useState, useRef, useCallback, useId } from 'react';
import { FormattedMessage } from 'react-intl';
@ -16,6 +16,7 @@ export const DomainPill: React.FC<{
username: string;
isSelf: boolean;
}> = ({ domain, username, isSelf }) => {
const accessibilityId = useId();
const [open, setOpen] = useState(false);
const [expanded, setExpanded] = useState(false);
const triggerRef = useRef(null);
@ -34,6 +35,8 @@ export const DomainPill: React.FC<{
className={classNames('account__domain-pill', { active: open })}
ref={triggerRef}
onClick={handleClick}
aria-expanded={open}
aria-controls={accessibilityId}
>
{domain}
</button>
@ -48,6 +51,8 @@ export const DomainPill: React.FC<{
{({ props }) => (
<div
{...props}
role='tooltip'
id={accessibilityId}
className='account__domain-pill__popout dropdown-animation'
>
<div className='account__domain-pill__popout__header'>

View File

@ -6,6 +6,7 @@ import classNames from 'classnames';
import Overlay from 'react-overlays/Overlay';
import { useSelectableClick } from '@/hooks/useSelectableClick';
import QuestionMarkIcon from '@/material-icons/400-24px/question_mark.svg?react';
import { Icon } from 'mastodon/components/icon';
@ -23,6 +24,8 @@ export const InfoButton: React.FC = () => {
setOpen(!open);
}, [open, setOpen]);
const [handleMouseDown, handleMouseUp] = useSelectableClick(handleClick);
return (
<>
<button
@ -46,10 +49,13 @@ export const InfoButton: React.FC = () => {
target={triggerRef}
>
{({ props }) => (
<div
<div // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
{...props}
className='dialog-modal__popout prose dropdown-animation'
role='tooltip'
id={accessibilityId}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
<FormattedMessage
id='info_button.what_is_alt_text'