fix(media viewer): lightbox focuses itself on open (keys worked only after a click); timeline viewer gets +/-/0 keys, double-click zoom and dialog semantics (#164)
CI / Build & Quality Checks (push) Successful in 1m31s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 5s
CI / Trigger Desktop Build (push) Successful in 7s
CI / Playwright smoke (e2e) (push) Successful in 2m19s
CI / Build & Quality Checks (push) Successful in 1m31s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 5s
CI / Trigger Desktop Build (push) Successful in 7s
CI / Playwright smoke (e2e) (push) Successful in 2m19s
Gallery lightbox: FocusTrap had initialFocus:false, so focus stayed on the tile behind the overlay and ←/→/Esc/+/- were dead until the user clicked inside. Timeline ImageViewer: no keyboard zoom, no role/aria-modal/label, focus landed on the <img>; now mirrors the lightbox (+ = / - / 0, double-click toggles 1×↔2×, role=dialog aria-modal labelled by the file name, focuses on open). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -302,6 +302,7 @@ function Lightbox({
|
||||
// Pan is only active for a zoomed-in image; usePan resets its offset when this
|
||||
// flips false (i.e. back to 1x, on navigation, or on a video).
|
||||
const { pan, cursor, onMouseDown, onTouchStart } = usePan(isImage && zoom !== 1);
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
const toggleZoom = useCallback(() => setZoom((z) => (z === 1 ? 2 : 1)), [setZoom]);
|
||||
|
||||
// Reset zoom when navigating to another item (and thus pan, via usePan).
|
||||
@@ -346,12 +347,17 @@ function Lightbox({
|
||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
// Focus the dialog itself on open: with `initialFocus: false` focus
|
||||
// stayed on the gallery tile behind the overlay, so ←/→/Esc/+/-
|
||||
// (handled by onKeyDown below) did nothing until the user clicked
|
||||
// inside the viewer (Gitea #164).
|
||||
initialFocus: () => dialogRef.current ?? false,
|
||||
clickOutsideDeactivates: false,
|
||||
escapeDeactivates: false,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={dialogRef}
|
||||
role="dialog"
|
||||
aria-modal
|
||||
aria-label="Media viewer"
|
||||
|
||||
Reference in New Issue
Block a user