Skip to content

Commit ce43465

Browse files
committed
chore(insights-hub): ensured links continue working on mobile
1 parent 57707a0 commit ce43465

File tree

7 files changed

+49
-166
lines changed

7 files changed

+49
-166
lines changed

apps/insights/src/components/Root/search-button.tsx

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import {
1414
Virtualizer,
1515
} from "@pythnetwork/component-library/Virtualizer";
1616
import type { Button as UnstyledButton } from "@pythnetwork/component-library/unstyled/Button";
17+
import type { ListBoxItemProps } from "@pythnetwork/component-library/unstyled/ListBox";
1718
import {
1819
ListBox,
1920
ListBoxItem,
2021
} from "@pythnetwork/component-library/unstyled/ListBox";
2122
import { useDrawer } from "@pythnetwork/component-library/useDrawer";
2223
import { useLogger } from "@pythnetwork/component-library/useLogger";
23-
import { useDetectBrowserInfo } from '@pythnetwork/react-hooks/use-detect-browser-info';
2424
import { matchSorter } from "match-sorter";
2525
import type { ReactNode } from "react";
2626
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -58,9 +58,9 @@ type ResolvedSearchButtonProps = {
5858
averageScore?: number | undefined;
5959
cluster: Cluster;
6060
} & (
61-
| { name: string; icon: ReactNode }
62-
| { name?: undefined; icon?: undefined }
63-
))[];
61+
| { name: string; icon: ReactNode }
62+
| { name?: undefined; icon?: undefined }
63+
))[];
6464
};
6565

6666
const ResolvedSearchButton = (props: ResolvedSearchButtonProps) => {
@@ -136,22 +136,59 @@ const SearchDialogContents = ({
136136
/** hooks */
137137
const drawer = useDrawer();
138138
const logger = useLogger();
139-
const browserInfo = useDetectBrowserInfo();
140139

141140
/** refs */
141+
const closeDrawerDebounceRef = useRef<NodeJS.Timeout | undefined>(undefined);
142142
const openTabModifierActiveRef = useRef(false);
143143
const middleMousePressedRef = useRef(false);
144144

145145
/** state */
146146
const [search, setSearch] = useState("");
147147
const [type, setType] = useState<ResultType | "">("");
148148

149+
/** callbacks */
149150
const closeDrawer = useCallback(() => {
150-
drawer.close().catch((error: unknown) => {
151-
logger.error(error);
152-
});
151+
if (closeDrawerDebounceRef.current) {
152+
clearTimeout(closeDrawerDebounceRef.current);
153+
closeDrawerDebounceRef.current = undefined;
154+
}
155+
156+
// we debounce the drawer closure because, if we don't,
157+
// mobile browsers (at least on iOS) may squash the native <a />
158+
// click, resulting in no price feed loading for the user
159+
closeDrawerDebounceRef.current = setTimeout(() => {
160+
drawer.close().catch((error: unknown) => {
161+
logger.error(error);
162+
});
163+
}, 250);
153164
}, [drawer, logger]);
165+
const onLinkPointerDown = useCallback<
166+
NonNullable<ListBoxItemProps<never>["onPointerDown"]>
167+
>((e) => {
168+
const { button, ctrlKey, metaKey } = e;
169+
170+
middleMousePressedRef.current = button === 1;
171+
172+
// on press is too abstracted and doesn't give us the native event
173+
// for determining if the user clicked their middle mouse button,
174+
// so we need to use the native onClick directly
175+
middleMousePressedRef.current = button === 1;
176+
openTabModifierActiveRef.current = metaKey || ctrlKey;
177+
}, []);
178+
const onLinkPointerUp = useCallback<
179+
NonNullable<ListBoxItemProps<never>["onPointerUp"]>
180+
>(() => {
181+
const userWantsNewTab =
182+
middleMousePressedRef.current || openTabModifierActiveRef.current;
183+
184+
// // they want a new tab, the search popover stays open
185+
if (!userWantsNewTab) closeDrawer();
186+
187+
middleMousePressedRef.current = false;
188+
openTabModifierActiveRef.current = false;
189+
}, [closeDrawer]);
154190

191+
/** memos */
155192
const results = useMemo(() => {
156193
const filteredFeeds = matchSorter(feeds, search, {
157194
keys: ["displaySymbol", "symbol", "description", "priceAccount"],
@@ -178,6 +215,7 @@ const SearchDialogContents = ({
178215
}
179216
return [...filteredFeeds, ...filteredPublishers];
180217
}, [feeds, publishers, search, type]);
218+
181219
return (
182220
<div className={styles.searchDialogContents}>
183221
<div className={styles.searchBar}>
@@ -247,23 +285,8 @@ const SearchDialogContents = ({
247285
: `/publishers/${ClusterToName[result.cluster]}/${encodeURIComponent(result.publisherKey)}`
248286
}
249287
data-is-first={result.id === results[0]?.id ? "" : undefined}
250-
onPointerDown={e => {
251-
middleMousePressedRef.current = e.button === 1;
252-
// on press is too abstracted and doesn't give us the native event
253-
// for determining if the user clicked their middle mouse button,
254-
// so we need to use the native onClick directly
255-
middleMousePressedRef.current = e.button === 1;
256-
openTabModifierActiveRef.current = browserInfo?.isMacOS ? e.metaKey : e.ctrlKey;
257-
}}
258-
onPointerUp={() => {
259-
const userWantsNewTab = middleMousePressedRef.current || openTabModifierActiveRef.current;
260-
261-
// they want a new tab, the search popover stays open
262-
if (!userWantsNewTab) closeDrawer();
263-
264-
middleMousePressedRef.current = false;
265-
openTabModifierActiveRef.current = false;
266-
}}
288+
onPointerDown={onLinkPointerDown}
289+
onPointerUp={onLinkPointerUp}
267290
>
268291
<div className={styles.smallScreen}>
269292
{result.type === ResultType.PriceFeed ? (

packages/component-library/src/unstyled/ListBox/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { usePrefetch } from "../../use-prefetch.js";
77

88
export { ListBox, ListBoxSection } from "react-aria-components";
99

10-
type ListBoxItemProps<T extends object> = ComponentProps<
10+
export type ListBoxItemProps<T extends object> = ComponentProps<
1111
typeof BaseListBoxItem<T>
1212
> & {
1313
prefetch?: Parameters<typeof usePrefetch>[0]["prefetch"];

packages/react-hooks/package.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"eslint": "catalog:"
2222
},
2323
"dependencies": {
24-
"ua-parser-js": "catalog:",
2524
"nuqs": "catalog:",
2625
"react": "catalog:",
2726
"react-dom": "catalog:"
@@ -44,14 +43,6 @@
4443
"types": "./dist/nuqs.d.ts",
4544
"default": "./dist/nuqs.mjs"
4645
},
47-
"./use-detect-browser-info": {
48-
"types": "./dist/use-detect-browser-info.d.ts",
49-
"default": "./dist/use-detect-browser-info.mjs"
50-
},
51-
"./use-previous": {
52-
"types": "./dist/use-previous.d.ts",
53-
"default": "./dist/use-previous.mjs"
54-
},
5546
"./package.json": "./package.json"
5647
}
5748
}

packages/react-hooks/src/use-detect-browser-info.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

packages/react-hooks/src/use-previous.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

pnpm-lock.yaml

Lines changed: 0 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ catalog:
161161
typedoc: ^0.26.8
162162
typescript: ^5.9.3
163163
turbo: ^2.5.8
164-
ua-parser-js: ^2.0.6
165164
vercel: ^41.4.1
166165
viem: ^2.37.13
167166
wagmi: ^2.14.16

0 commit comments

Comments
 (0)