From 796187c1e8a387d94892e39cc8b897866e616d4d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 29 Jan 2025 13:51:47 +0100 Subject: [PATCH] Add ability to dismiss alt text badge by tapping it in web UI (#33737) --- app/javascript/hooks/useSelectableClick.ts | 55 +++++++++++++++++++ .../mastodon/components/alt_text_badge.tsx | 16 +++++- .../account/components/domain_pill.tsx | 7 ++- .../alt_text_modal/components/info_button.tsx | 8 ++- 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 app/javascript/hooks/useSelectableClick.ts diff --git a/app/javascript/hooks/useSelectableClick.ts b/app/javascript/hooks/useSelectableClick.ts new file mode 100644 index 0000000000..c8f16f0b0f --- /dev/null +++ b/app/javascript/hooks/useSelectableClick.ts @@ -0,0 +1,55 @@ +import { useRef, useCallback } from 'react'; + +type Position = [number, number]; + +export const useSelectableClick = ( + onClick: React.MouseEventHandler, + maxDelta = 5, +) => { + const clickPositionRef = useRef(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; +}; diff --git a/app/javascript/mastodon/components/alt_text_badge.tsx b/app/javascript/mastodon/components/alt_text_badge.tsx index 99bec1ee51..466c5cf1bc 100644 --- a/app/javascript/mastodon/components/alt_text_badge.tsx +++ b/app/javascript/mastodon/components/alt_text_badge.tsx @@ -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(null); const [open, setOpen] = useState(false); @@ -25,12 +28,16 @@ export const AltTextBadge: React.FC<{ setOpen(false); }, [setOpen]); + const [handleMouseDown, handleMouseUp] = useSelectableClick(handleClose); + return ( <> @@ -47,9 +54,12 @@ export const AltTextBadge: React.FC<{ > {({ props }) => (
-