Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to
### Changed

- ♿️(frontend) use semantic `<dl>` structure in document info card #2379
- ♿️(frontend) restore presenter focus trapping after share links #2533

## [v5.4.1] - 2026-07-09

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const renderShortcuts = (
onToggleFullscreen: vi.fn(),
onClose: vi.fn(),
isFullscreen: false,
isPopoverOpen: false,
...overrides,
};
renderHook(() => usePresenterShortcuts(handlers));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface PresenterFloatingBarProps {
onPrev: () => void;
onNext: () => void;
onCopyLink: () => void;
onActionsOpenChange?: (isOpen: boolean) => void;
onToggleFullscreen: () => void;
onClose: () => void;
}
Expand All @@ -43,6 +44,11 @@ const barCss = css`
border: 1px solid var(--c--contextuals--border--surface--primary);
background: var(--c--contextuals--background--surface--primary);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.05);

button[aria-disabled='true'] {
opacity: 0.4;
cursor: default;
}
`;

const separatorCss = css`
Expand Down Expand Up @@ -71,6 +77,12 @@ const PresenterDropdownLayerStyle = createGlobalStyle`
box-sizing: border-box;
height: 32px;
}

.react-aria-Popover .c__dropdown-menu--tiny .c__dropdown-menu-item:focus-visible {
outline: 2px solid var(--c--theme--colors--primary-400, #3b82f6);
outline-offset: -2px;
border-radius: 4px;
}
`;

export const PresenterFloatingBar = ({
Expand All @@ -80,6 +92,7 @@ export const PresenterFloatingBar = ({
onPrev,
onNext,
onCopyLink,
onActionsOpenChange,
onToggleFullscreen,
onClose,
}: PresenterFloatingBarProps) => {
Expand All @@ -97,7 +110,7 @@ export const PresenterFloatingBar = ({
useEffect(() => {
const id = requestAnimationFrame(() => {
barRef.current
?.querySelector<HTMLButtonElement>('button:not([disabled])')
?.querySelector<HTMLButtonElement>('button:not([aria-disabled="true"])')
?.focus();
});
return () => cancelAnimationFrame(id);
Expand All @@ -108,7 +121,16 @@ export const PresenterFloatingBar = ({
const toggleActions = (event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
event.preventDefault();
setIsActionsOpen((isOpen) => !isOpen);
setIsActionsOpen((prev) => {
const next = !prev;
onActionsOpenChange?.(next);
return next;
});
};

const handleActionsOpenChange = (isOpen: boolean) => {
setIsActionsOpen(isOpen);
onActionsOpenChange?.(isOpen);
};

const actionOptions = useMemo<DropdownMenuItem[]>(
Expand Down Expand Up @@ -137,8 +159,8 @@ export const PresenterFloatingBar = ({
size="nano"
color="neutral"
variant="tertiary"
disabled={isFirst}
onClick={onPrev}
aria-disabled={isFirst}
onClick={isFirst ? undefined : onPrev}
aria-label={t('Previous slide')}
icon={<ChevronLeft size="small" />}
/>
Expand All @@ -149,16 +171,16 @@ export const PresenterFloatingBar = ({
size="nano"
color="neutral"
variant="tertiary"
disabled={isLast}
onClick={onNext}
aria-disabled={isLast}
onClick={isLast ? undefined : onNext}
aria-label={t('Next slide')}
icon={<ChevronRight size="small" />}
/>
<Box $css={separatorCss} aria-hidden />
<DropdownMenu
options={actionOptions}
isOpen={isActionsOpen}
onOpenChange={setIsActionsOpen}
onOpenChange={handleActionsOpenChange}
shouldCloseOnInteractOutside={() => true}
variant="tiny"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export const PresenterOverlay = ({
const editor = useEditorStore((state) => state.editor);
const copyPresenterLink = useCopyPresenterLink(doc.id);

// Track the floating bar's actions popover state so keyboard shortcuts
// can avoid closing the presenter while the popover is open.
const [isActionsOpen, setIsActionsOpen] = useState(false);

// Snapshot the editor's blocks once at mount. Subsequent collaborator
// edits do not affect the ongoing presentation (by design).
const snapshotRef = useRef<PresenterBlock[] | null>(null);
Expand Down Expand Up @@ -138,6 +142,7 @@ export const PresenterOverlay = ({
onToggleFullscreen: () => void toggle(),
onClose,
isFullscreen,
isPopoverOpen: isActionsOpen,
});

const mountedIndices = useMemo(() => {
Expand Down Expand Up @@ -173,7 +178,7 @@ export const PresenterOverlay = ({
}

return createPortal(
<FocusScope autoFocus restoreFocus>
<FocusScope contain={!isActionsOpen} autoFocus restoreFocus>
<Box
$css={overlayCss}
role="dialog"
Expand Down Expand Up @@ -202,6 +207,7 @@ export const PresenterOverlay = ({
onPrev={goPrev}
onNext={goNext}
onCopyLink={() => copyPresenterLink(currentIndex)}
onActionsOpenChange={setIsActionsOpen}
onToggleFullscreen={() => void toggle()}
onClose={onClose}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface ShortcutHandlers {
onToggleFullscreen: () => void;
onClose: () => void;
isFullscreen: boolean;
isPopoverOpen: boolean;
}

const ARROW_CODES = new Set(['ArrowLeft', 'ArrowRight']);
Expand All @@ -20,6 +21,7 @@ export const usePresenterShortcuts = ({
onToggleFullscreen,
onClose,
isFullscreen,
isPopoverOpen,
}: ShortcutHandlers) => {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
Expand Down Expand Up @@ -74,8 +76,10 @@ export const usePresenterShortcuts = ({
case 'Escape':
// While fullscreen, the browser handles Esc natively (exits
// fullscreen) and we deliberately stay open. Once out of
// fullscreen, Esc closes the presenter.
if (!isFullscreen) {
// fullscreen, Esc closes the presenter — unless the presenter's
// own actions popover is open, in which case Esc should only
// dismiss the popover.
if (!isFullscreen && !isPopoverOpen) {
event.preventDefault();
onClose();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand All @@ -95,5 +99,6 @@ export const usePresenterShortcuts = ({
onToggleFullscreen,
onClose,
isFullscreen,
isPopoverOpen,
]);
};
Loading