From 987ef63e64fc180b2eb4a9742cebefed1f1d208f Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 26 Feb 2025 14:52:48 +0530 Subject: [PATCH] (feat:widget) simplify scrolling --- extensions/react-widget/package.json | 2 +- .../src/components/DocsGPTWidget.tsx | 54 ++++++++++++------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index 75239685..ca2b48f6 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -1,6 +1,6 @@ { "name": "docsgpt", - "version": "0.4.9", + "version": "0.4.11", "private": false, "description": "DocsGPT 🦖 is an innovative open-source tool designed to simplify the retrieval of information from project documentation using advanced GPT models 🤖.", "source": "./src/index.html", diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 142853e2..5ce9140a 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { useRef } from 'react' +import React, { useRef, useState, useEffect } from 'react' import DOMPurify from 'dompurify'; import styled, { keyframes, css } from 'styled-components'; import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon } from '@radix-ui/react-icons'; @@ -591,10 +591,10 @@ export const DocsGPTWidget = (props: WidgetProps) => { ) } + export const WidgetCore = ({ - apiHost = 'http://localhost:7091', - apiKey = "1a31e931-90c9-4fb7-af99-2cba70a0f3ee", - //apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', + apiHost = 'https://gptcloud.arc53.com', + apiKey = "82962c9a-aa77-4152-94e5-a4f84fd44c6a", avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png', title = 'Get AI assistance', description = 'DocsGPT\'s AI Chatbot is here to help', @@ -614,8 +614,10 @@ export const WidgetCore = ({ const [queries, setQueries] = React.useState([]); const [conversationId, setConversationId] = React.useState(null); const [eventInterrupt, setEventInterrupt] = React.useState(false); //click or scroll by user while autoScrolling + const [hasScrolledToLast, setHasScrolledToLast] = useState(true); const isBubbleHovered = useRef(false); + const conversationRef = useRef(null); const endMessageRef = React.useRef(null); const md = new MarkdownIt(); @@ -632,26 +634,38 @@ export const WidgetCore = ({ } }, [isOpen]); - - const handleUserInterrupt = () => { - (status === 'loading') && setEventInterrupt(true); + if (!eventInterrupt && status === 'loading') setEventInterrupt(true); } - const scrollToBottom = (element: Element | null) => { - //recursive function to scroll to the last child of the last child ... - // to get to the bottom most element - if (!element) return; - if (element?.children.length === 0) { - element?.scrollIntoView({ + + const scrollIntoView = () => { + if (!conversationRef?.current || eventInterrupt) return; + + if (status === 'idle' || !queries.length || !queries[queries.length - 1].response) { + conversationRef.current.scrollTo({ behavior: 'smooth', - block: 'start', + top: conversationRef.current.scrollHeight, }); + } else { + conversationRef.current.scrollTop = conversationRef.current.scrollHeight; } - const lastChild = element?.children?.[element.children.length - 1] - lastChild && scrollToBottom(lastChild) + setHasScrolledToLast(true); }; + + const checkScroll = () => { + const el = conversationRef.current; + if (!el) return; + const isBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10; + setHasScrolledToLast(isBottom); + }; + React.useEffect(() => { - !eventInterrupt && scrollToBottom(endMessageRef.current); + !eventInterrupt && scrollIntoView(); + + conversationRef.current?.addEventListener('scroll', checkScroll); + return () => { + conversationRef.current?.removeEventListener('scroll', checkScroll); + }; }, [queries.length, queries[queries.length - 1]?.response]); async function handleFeedback(feedback: FEEDBACK, index: number) { @@ -804,7 +818,11 @@ export const WidgetCore = ({ - + { queries.length > 0 ? queries?.map((query, index) => { return (