From 3250e34cad95158c998b2110eeb47c1cc5c62ef4 Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Sun, 12 Nov 2023 08:09:19 +0800 Subject: [PATCH] fix browser scrollable bug --- app/src/components/home/ChatInterface.tsx | 20 ++++++++++- app/src/conf.ts | 2 +- app/src/utils/dom.ts | 43 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/app/src/components/home/ChatInterface.tsx b/app/src/components/home/ChatInterface.tsx index 04839a3..efab200 100644 --- a/app/src/components/home/ChatInterface.tsx +++ b/app/src/components/home/ChatInterface.tsx @@ -5,6 +5,7 @@ import { selectCurrent, selectMessages } from "@/store/chat.ts"; import MessageSegment from "@/components/Message.tsx"; import { connectionEvent } from "@/events/connection.ts"; import { chatEvent } from "@/events/chat.ts"; +import {addEventListeners} from "@/utils/dom.ts"; type ChatInterfaceProps = { setTarget: (target: HTMLDivElement | null) => void; @@ -14,10 +15,11 @@ function ChatInterface({ setTarget }: ChatInterfaceProps) { const ref = React.useRef(null); const messages: Message[] = useSelector(selectMessages); const current: number = useSelector(selectCurrent); + const [scrollable, setScrollable] = React.useState(true); useEffect( function () { - if (!ref.current) return; + if (!ref.current || !scrollable) return; const el = ref.current as HTMLDivElement; el.scrollTop = el.scrollHeight; chatEvent.emit(); @@ -25,6 +27,22 @@ function ChatInterface({ setTarget }: ChatInterfaceProps) { [messages], ); + useEffect(() => { + if (!ref.current) return; + const el = ref.current as HTMLDivElement; + + const event = () => { + setScrollable( + el.scrollTop + el.clientHeight + 100 >= el.scrollHeight, + ); + } + + return addEventListeners(el, [ + "scroll", "resize", "touchmove", + "touchend", "touchcancel", + ], event); + }, [ref]); + useEffect(() => { setTarget(ref.current); }, [ref]); diff --git a/app/src/conf.ts b/app/src/conf.ts index 3a8f37d..17c9dff 100644 --- a/app/src/conf.ts +++ b/app/src/conf.ts @@ -8,7 +8,7 @@ import { } from "@/utils/env.ts"; import { getMemory } from "@/utils/memory.ts"; -export const version = "3.6.18"; +export const version = "3.6.19"; export const dev: boolean = getDev(); export const deploy: boolean = true; export let rest_api: string = getRestApi(deploy); diff --git a/app/src/utils/dom.ts b/app/src/utils/dom.ts index 14d87bf..30a1edd 100644 --- a/app/src/utils/dom.ts +++ b/app/src/utils/dom.ts @@ -157,3 +157,46 @@ export function useInputValue(id: string, value: string) { const input = document.getElementById(id) as HTMLInputElement | undefined; return input && replaceInputValue(input, value) && input.focus(); } + +export function addEventListener( + el: HTMLElement, + event: string, + handler: EventListenerOrEventListenerObject, +): () => void { + /** + * Add event listener to element + * @param el Element + * @param event Event name + * @param handler Event handler + * @example + * const el = document.getElementById("el"); + * const handler = () => console.log("Hello world!"); + * const remove = addEventListener(el, "click", handler); + * remove(); + */ + + el.addEventListener(event, handler); + return () => el.removeEventListener(event, handler); +} + + +export function addEventListeners( + el: HTMLElement, + events: string[], + handler: EventListenerOrEventListenerObject, +): () => void { + /** + * Add event listeners to element + * @param el Element + * @param events Event names + * @param handler Event handler + * @example + * const el = document.getElementById("el"); + * const handler = () => console.log("Hello world!"); + * const remove = addEventListeners(el, ["click", "touchstart"], handler); + * remove(); + */ + + events.forEach((event) => el.addEventListener(event, handler)); + return () => events.forEach((event) => el.removeEventListener(event, handler)); +}