mirror of
https://seed.radicle.dev/rad:z4D5UCArafTzTQpDZNQRuqswh3ury.git
synced 2026-11-09 21:30:38 +08:00
72 lines
1.7 KiB
Svelte
72 lines
1.7 KiB
Svelte
<script lang="ts" module>
|
|
import { getContext } from "svelte";
|
|
|
|
const SCROLL_VIEWPORT_CONTEXT = Symbol("scroll-viewport");
|
|
|
|
export function getScrollViewport(): () => HTMLElement | undefined {
|
|
return (
|
|
getContext<() => HTMLElement | undefined>(SCROLL_VIEWPORT_CONTEXT) ??
|
|
(() => undefined)
|
|
);
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import type { Snippet } from "svelte";
|
|
|
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-svelte";
|
|
import { setContext } from "svelte";
|
|
|
|
interface Props {
|
|
children: Snippet;
|
|
style?: string;
|
|
onScrollHalf?: () => void;
|
|
}
|
|
|
|
const {
|
|
children,
|
|
style = "height: 100%;",
|
|
onScrollHalf = undefined,
|
|
}: Props = $props();
|
|
|
|
let viewport: HTMLElement | undefined = $state(undefined);
|
|
setContext(SCROLL_VIEWPORT_CONTEXT, () => viewport);
|
|
|
|
function shouldLoadMore(instance: {
|
|
elements(): { target: HTMLElement };
|
|
}): boolean {
|
|
const el = instance.elements().target;
|
|
const threshold = 200;
|
|
|
|
return el.scrollTop + el.clientHeight >= el.scrollHeight - threshold;
|
|
}
|
|
|
|
const scrollHalfHandler = $derived(
|
|
onScrollHalf
|
|
? (instance: Parameters<typeof shouldLoadMore>[0]) => {
|
|
if (shouldLoadMore(instance)) {
|
|
onScrollHalf();
|
|
}
|
|
}
|
|
: undefined,
|
|
);
|
|
</script>
|
|
|
|
<OverlayScrollbarsComponent
|
|
element="div"
|
|
{style}
|
|
options={{
|
|
scrollbars: { theme: "global-os-theme-radicle", autoHide: "scroll" },
|
|
}}
|
|
events={{
|
|
initialized: instance => {
|
|
viewport = instance.elements().viewport;
|
|
scrollHalfHandler?.(instance);
|
|
},
|
|
scroll: scrollHalfHandler,
|
|
updated: scrollHalfHandler,
|
|
}}
|
|
defer>
|
|
{@render children()}
|
|
</OverlayScrollbarsComponent>
|