Skip to content

Commit 888ab90

Browse files
authored
Merge pull request #301 from SableClient/fix/url-preview-scroll-arrows
fix(url-preview): show scroll arrows only when content overflows
2 parents cb7934f + f7afb8d commit 888ab90

2 files changed

Lines changed: 31 additions & 42 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
default: patch
3+
---
4+
5+
Fix URL preview scroll arrows appearing when there is no content to scroll

src/app/components/url-preview/UrlPreviewCard.tsx

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import { IPreviewUrlResponse } from '$types/matrix-sdk';
33
import { Box, Icon, IconButton, Icons, Scroll, Spinner, Text, as, color, config } from 'folds';
44
import { AsyncStatus, useAsyncCallback } from '$hooks/useAsyncCallback';
55
import { useMatrixClient } from '$hooks/useMatrixClient';
6-
import {
7-
getIntersectionObserverEntry,
8-
useIntersectionObserver,
9-
} from '$hooks/useIntersectionObserver';
106
import { mxcUrlToHttp, downloadMedia } from '$utils/matrix';
117
import { useMediaAuthentication } from '$hooks/useMediaAuthentication';
128
import * as css from './UrlPreviewCard.css';
@@ -242,43 +238,34 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number; mediaType?: s
242238

243239
export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
244240
const scrollRef = useRef<HTMLDivElement>(null);
245-
const backAnchorRef = useRef<HTMLDivElement>(null);
246-
const frontAnchorRef = useRef<HTMLDivElement>(null);
247-
const [backVisible, setBackVisible] = useState(true);
248-
const [frontVisible, setFrontVisible] = useState(true);
241+
const innerBoxRef = useRef<HTMLDivElement>(null);
242+
const [canScrollLeft, setCanScrollLeft] = useState(false);
243+
const [canScrollRight, setCanScrollRight] = useState(false);
249244

250-
const intersectionObserver = useIntersectionObserver(
251-
useCallback((entries) => {
252-
const backAnchor = backAnchorRef.current;
253-
const frontAnchor = frontAnchorRef.current;
254-
const backEntry = backAnchor && getIntersectionObserverEntry(backAnchor, entries);
255-
const frontEntry = frontAnchor && getIntersectionObserverEntry(frontAnchor, entries);
256-
if (backEntry) {
257-
setBackVisible(backEntry.isIntersecting);
258-
}
259-
if (frontEntry) {
260-
setFrontVisible(frontEntry.isIntersecting);
261-
}
262-
}, []),
263-
useCallback(
264-
() => ({
265-
root: scrollRef.current,
266-
rootMargin: '10px',
267-
}),
268-
[]
269-
)
270-
);
245+
const updateArrows = useCallback(() => {
246+
const scroll = scrollRef.current;
247+
if (!scroll) return;
248+
const { scrollLeft, scrollWidth, clientWidth } = scroll;
249+
setCanScrollLeft(scrollLeft > 1);
250+
setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);
251+
}, []);
271252

272253
useEffect(() => {
273-
const backAnchor = backAnchorRef.current;
274-
const frontAnchor = frontAnchorRef.current;
275-
if (backAnchor) intersectionObserver?.observe(backAnchor);
276-
if (frontAnchor) intersectionObserver?.observe(frontAnchor);
254+
const scroll = scrollRef.current;
255+
if (!scroll) return undefined;
256+
257+
updateArrows();
258+
scroll.addEventListener('scroll', updateArrows, { passive: true });
259+
260+
const resizeObserver = new ResizeObserver(updateArrows);
261+
resizeObserver.observe(scroll);
262+
if (innerBoxRef.current) resizeObserver.observe(innerBoxRef.current);
263+
277264
return () => {
278-
if (backAnchor) intersectionObserver?.unobserve(backAnchor);
279-
if (frontAnchor) intersectionObserver?.unobserve(frontAnchor);
265+
scroll.removeEventListener('scroll', updateArrows);
266+
resizeObserver.disconnect();
280267
};
281-
}, [intersectionObserver]);
268+
}, [updateArrows]);
282269

283270
const handleScrollBack = () => {
284271
const scroll = scrollRef.current;
@@ -308,8 +295,7 @@ export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
308295
>
309296
<Scroll ref={scrollRef} direction="Horizontal" size="0" visibility="Hover" hideTrack>
310297
<Box shrink="No" alignItems="Center">
311-
<div ref={backAnchorRef} />
312-
{!backVisible && (
298+
{canScrollLeft && (
313299
<>
314300
<div className={css.UrlPreviewHolderGradient({ position: 'Left' })} />
315301
<IconButton
@@ -324,10 +310,9 @@ export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
324310
</IconButton>
325311
</>
326312
)}
327-
<Box alignItems="Inherit" gap="200">
313+
<Box ref={innerBoxRef} alignItems="Inherit" gap="200">
328314
{children}
329-
330-
{!frontVisible && (
315+
{canScrollRight && (
331316
<>
332317
<div className={css.UrlPreviewHolderGradient({ position: 'Right' })} />
333318
<IconButton
@@ -342,7 +327,6 @@ export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
342327
</IconButton>
343328
</>
344329
)}
345-
<div ref={frontAnchorRef} />
346330
</Box>
347331
</Box>
348332
</Scroll>

0 commit comments

Comments
 (0)