fix: ESC for back in SharePopover not working (#11662)

* fix: ESC for back in SharePopover not working

closes #11656

* Normalize prevent default callbacks
This commit is contained in:
Tom Moor
2026-03-05 17:44:48 -05:00
committed by GitHub
parent 80c1e5a10b
commit d8b0e731ef
8 changed files with 27 additions and 20 deletions
+2 -6
View File
@@ -3,6 +3,7 @@ import { actionToMenuItem } from "~/actions";
import useActionContext from "~/hooks/useActionContext";
import useMobile from "~/hooks/useMobile";
import type { ActionVariant, ActionWithChildren } from "~/types";
import { preventDefault } from "~/utils/events";
import { toMenuItems } from "./transformer";
import { observer } from "mobx-react";
import { useComputed } from "~/hooks/useComputed";
@@ -61,11 +62,6 @@ export const ContextMenu = observer(
}
}, []);
const handleCloseAutoFocus = React.useCallback(
(e: Event) => e.preventDefault(),
[]
);
if (isMobile || !action || menuItems.length === 0) {
return <>{children}</>;
}
@@ -80,7 +76,7 @@ export const ContextMenu = observer(
aria-label={ariaLabel}
onAnimationStart={disablePointerEvents}
onAnimationEnd={enablePointerEvents}
onCloseAutoFocus={handleCloseAutoFocus}
onCloseAutoFocus={preventDefault}
>
{content}
</MenuContent>
+2 -6
View File
@@ -13,6 +13,7 @@ import { MenuProvider } from "~/components/primitives/Menu/MenuContext";
import { actionToMenuItem } from "~/actions";
import useActionContext from "~/hooks/useActionContext";
import useMobile from "~/hooks/useMobile";
import { preventDefault } from "~/utils/events";
import type {
ActionVariant,
ActionWithChildren,
@@ -98,11 +99,6 @@ export const DropdownMenu = observer(
}
}, []);
const handleCloseAutoFocus = React.useCallback(
(e: Event) => e.preventDefault(),
[]
);
if (isMobile) {
return (
<MobileDropdown
@@ -129,7 +125,7 @@ export const DropdownMenu = observer(
aria-label={ariaLabel}
onAnimationStart={disablePointerEvents}
onAnimationEnd={enablePointerEvents}
onCloseAutoFocus={handleCloseAutoFocus}
onCloseAutoFocus={preventDefault}
>
{content}
{append}
+2 -1
View File
@@ -16,6 +16,7 @@ import {
import { id as bodyContentId } from "~/components/SkipNavContent";
import useKeyDown from "~/hooks/useKeyDown";
import useStores from "~/hooks/useStores";
import { preventDefault } from "~/utils/events";
import type { SearchResult } from "~/types";
import SearchListItem from "./SearchListItem";
@@ -230,7 +231,7 @@ function SearchPopover({ shareId, className }: Props) {
align="start"
shrink
onEscapeKeyDown={handleEscapeList}
onOpenAutoFocus={(e) => e.preventDefault()}
onOpenAutoFocus={preventDefault}
onInteractOutside={(event) => {
const target = event.target as Element | null;
if (target === searchInputRef.current) {
+7 -2
View File
@@ -63,9 +63,14 @@ window.addEventListener("keydown", (event) => {
return;
}
// Track whether defaultPrevented was already set by an external handler (e.g.
// Radix UI's DismissableLayer) so we only break on preventDefault calls made
// by our own callbacks.
const wasDefaultPrevented = event.defaultPrevented;
// reverse so that the last registered callbacks get executed first
for (const registered of callbacks.reverse()) {
if (event.defaultPrevented === true) {
for (const registered of [...callbacks].reverse()) {
if (!wasDefaultPrevented && event.defaultPrevented) {
break;
}
@@ -12,6 +12,7 @@ import {
import useCurrentTeam from "~/hooks/useCurrentTeam";
import useMobile from "~/hooks/useMobile";
import useStores from "~/hooks/useStores";
import { preventDefault } from "~/utils/events";
import lazyWithRetry from "~/utils/lazyWithRetry";
const SharePopover = lazyWithRetry(
@@ -64,6 +65,7 @@ function ShareButton({ collection }: Props) {
minHeight={175}
side="bottom"
align="end"
onEscapeKeyDown={preventDefault}
>
<Suspense fallback={null}>
<SharePopover
@@ -11,6 +11,7 @@ import {
} from "~/components/primitives/Popover";
import useMobile from "~/hooks/useMobile";
import useStores from "~/hooks/useStores";
import { preventDefault } from "~/utils/events";
import lazyWithRetry from "~/utils/lazyWithRetry";
const SharePopover = lazyWithRetry(
@@ -58,6 +59,7 @@ function ShareButton({ document }: Props) {
minHeight={175}
side="bottom"
align="end"
onEscapeKeyDown={preventDefault}
>
<Suspense fallback={null}>
<SharePopover
+2 -5
View File
@@ -28,6 +28,7 @@ import usePaginatedRequest from "~/hooks/usePaginatedRequest";
import useQuery from "~/hooks/useQuery";
import useStores from "~/hooks/useStores";
import type { PaginationParams, SearchResult } from "~/types";
import { preventDefault } from "~/utils/events";
import { searchPath } from "~/utils/routeHelpers";
import { decodeURIComponentSafe } from "~/utils/urls";
import CollectionFilter from "./components/CollectionFilter";
@@ -251,11 +252,7 @@ function Search() {
<RegisterKeyDown trigger="Escape" handler={history.goBack} />
{loading && <LoadingIndicator />}
<ResultsWrapper column auto>
<form
method="GET"
action={searchPath()}
onSubmit={(ev) => ev.preventDefault()}
>
<form method="GET" action={searchPath()} onSubmit={preventDefault}>
<SearchInput
name="query"
key={query ? "search" : "recent"}
+8
View File
@@ -0,0 +1,8 @@
/**
* Calls preventDefault on the event. Useful as a stable callback reference.
*
* @param event the event to prevent default on.
*/
export const preventDefault = (event: { preventDefault: () => void }) => {
event.preventDefault();
};