import React, { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; import { Box, Chip, Header, Icon, IconButton, Icons, Text, as } from 'folds'; import { useSaveFile } from '../../hooks/useSaveFile'; import * as css from './ImageViewer.css'; import { useZoom } from '../../hooks/useZoom'; import { usePan } from '../../hooks/usePan'; import { downloadMedia } from '../../utils/matrix'; import { MobileTouchTarget } from '../../styles/mobile.css'; export type ImageViewerProps = { alt: string; src: string; requestClose: () => void; }; export const ImageViewer = as<'div', ImageViewerProps>( ({ className, alt, src, requestClose, ...props }, ref) => { const { t } = useTranslation(); const saveFile = useSaveFile(); const { zoom, zoomIn, zoomOut, setZoom } = useZoom(0.2); const { pan, cursor, onMouseDown, onTouchStart } = usePan(zoom !== 1); const handleDownload = async () => { const fileContent = await downloadMedia(src); saveFile(fileContent, alt); }; // [Gitea #164] Same keyboard model as the gallery lightbox: + / = zoom // in, - zoom out, 0 reset; double-click toggles 1× ↔ 2×. The root takes // focus on open so those keys (and Escape, handled by the modal) work // immediately instead of only after clicking inside the viewer. const rootRef = useRef(null); useEffect(() => { rootRef.current?.focus({ preventScroll: true }); }, []); const handleKeyDown = (evt: React.KeyboardEvent) => { if (evt.key === '+' || evt.key === '=') zoomIn(); else if (evt.key === '-') zoomOut(); else if (evt.key === '0') setZoom(1); else return; evt.preventDefault(); }; return ( { rootRef.current = node; if (typeof ref === 'function') ref(node); else if (ref) (ref as React.MutableRefObject).current = node; }} >
{alt} setZoom(zoom === 1 ? 2 : 1)} > {Math.round(zoom * 100)}% 1 ? 'Success' : 'SurfaceVariant'} outlined={zoom > 1} size="300" radii="Pill" className={MobileTouchTarget} onClick={zoomIn} aria-label="Zoom In" > } > {t('Organisms.ImageViewer.download')}
{ if (evt.deltaY < 0) zoomIn(); else if (evt.deltaY > 0) zoomOut(); }} > {alt} setZoom(zoom === 1 ? 2 : 1)} />
); }, );