Skip to content

Commit

Permalink
Add ability to dismiss alt text badge by tapping it in web UI (mastod…
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron authored Jan 29, 2025
1 parent 2d545c5 commit 796187c
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 5 deletions.
55 changes: 55 additions & 0 deletions app/javascript/hooks/useSelectableClick.ts
Original file line number Diff line number Diff line change
@@ -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;
};
16 changes: 13 additions & 3 deletions app/javascript/mastodon/components/alt_text_badge.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useCallback, useRef } from 'react';
import { useState, useCallback, useRef, useId } from 'react';

import { FormattedMessage } from 'react-intl';

Expand All @@ -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);

Expand All @@ -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>
Expand All @@ -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'
role='region'
id={accessibilityId}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
<h4>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useRef, useCallback } from 'react';
import { useState, useRef, useCallback, useId } from 'react';

import { FormattedMessage } from 'react-intl';

Expand All @@ -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);
Expand All @@ -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>
Expand All @@ -48,6 +51,8 @@ export const DomainPill: React.FC<{
{({ props }) => (
<div
{...props}
role='region'
id={accessibilityId}
className='account__domain-pill__popout dropdown-animation'
>
<div className='account__domain-pill__popout__header'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -23,6 +24,8 @@ export const InfoButton: React.FC = () => {
setOpen(!open);
}, [open, setOpen]);

const [handleMouseDown, handleMouseUp] = useSelectableClick(handleClick);

return (
<>
<button
Expand All @@ -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='region'
id={accessibilityId}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
<FormattedMessage
id='info_button.what_is_alt_text'
Expand Down

0 comments on commit 796187c

Please sign in to comment.