UNPKG

@assistant-ui/react

Version:

Typescript/React library for AI Chat

1 lines 4.48 kB
{"version":3,"sources":["../../../src/primitives/thread/useThreadViewportAutoScroll.tsx"],"sourcesContent":["\"use client\";\n\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { RefCallback, useEffect, useRef } from \"react\";\nimport { useThreadRuntime } from \"../../context/react/ThreadContext\";\nimport { useOnResizeContent } from \"../../utils/hooks/useOnResizeContent\";\nimport { useOnScrollToBottom } from \"../../utils/hooks/useOnScrollToBottom\";\nimport { useManagedRef } from \"../../utils/hooks/useManagedRef\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { useThreadViewportStore } from \"../../context/react/ThreadViewportContext\";\n\nexport namespace useThreadViewportAutoScroll {\n export type Options = {\n autoScroll?: boolean | undefined;\n };\n}\n\nexport const useThreadViewportAutoScroll = <TElement extends HTMLElement>({\n autoScroll = true,\n}: useThreadViewportAutoScroll.Options): RefCallback<TElement> => {\n const divRef = useRef<TElement>(null);\n\n const threadViewportStore = useThreadViewportStore();\n\n const lastScrollTop = useRef<number>(0);\n\n // bug: when ScrollToBottom's button changes its disabled state, the scroll stops\n // fix: delay the state change until the scroll is done\n const isScrollingToBottomRef = useRef(false);\n\n const scrollToBottom = (behavior: ScrollBehavior) => {\n const div = divRef.current;\n if (!div || !autoScroll) return;\n\n isScrollingToBottomRef.current = true;\n div.scrollTo({ top: div.scrollHeight, behavior });\n };\n\n const handleScroll = () => {\n const div = divRef.current;\n if (!div) return;\n\n const isAtBottom = threadViewportStore.getState().isAtBottom;\n const newIsAtBottom =\n div.scrollHeight - div.scrollTop <= div.clientHeight + 1; // TODO figure out why +1 is needed\n\n if (!newIsAtBottom && lastScrollTop.current < div.scrollTop) {\n // ignore scroll down\n } else {\n if (newIsAtBottom) {\n isScrollingToBottomRef.current = false;\n }\n\n if (newIsAtBottom !== isAtBottom) {\n writableStore(threadViewportStore).setState({\n isAtBottom: newIsAtBottom,\n });\n }\n }\n\n lastScrollTop.current = div.scrollTop;\n };\n\n const resizeRef = useOnResizeContent(() => {\n if (\n isScrollingToBottomRef.current ||\n threadViewportStore.getState().isAtBottom\n ) {\n scrollToBottom(\"instant\");\n }\n\n handleScroll();\n });\n\n const scrollRef = useManagedRef<HTMLElement>((el) => {\n el.addEventListener(\"scroll\", handleScroll);\n return () => {\n el.removeEventListener(\"scroll\", handleScroll);\n };\n });\n\n useOnScrollToBottom(() => {\n scrollToBottom(\"auto\");\n });\n\n // autoscroll on run start\n const threadRuntime = useThreadRuntime();\n useEffect(() => {\n return threadRuntime.unstable_on(\"run-start\", () => scrollToBottom(\"auto\"));\n }, [scrollToBottom, threadRuntime]);\n\n const autoScrollRef = useComposedRefs<TElement>(resizeRef, scrollRef, divRef);\n return autoScrollRef;\n};\n"],"mappings":";;;AAEA,SAAS,uBAAuB;AAChC,SAAsB,WAAW,cAAc;AAC/C,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAQhC,IAAM,8BAA8B,CAA+B;AAAA,EACxE,aAAa;AACf,MAAkE;AAChE,QAAM,SAAS,OAAiB,IAAI;AAEpC,QAAM,sBAAsB,uBAAuB;AAEnD,QAAM,gBAAgB,OAAe,CAAC;AAItC,QAAM,yBAAyB,OAAO,KAAK;AAE3C,QAAM,iBAAiB,CAAC,aAA6B;AACnD,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,OAAO,CAAC,WAAY;AAEzB,2BAAuB,UAAU;AACjC,QAAI,SAAS,EAAE,KAAK,IAAI,cAAc,SAAS,CAAC;AAAA,EAClD;AAEA,QAAM,eAAe,MAAM;AACzB,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,IAAK;AAEV,UAAM,aAAa,oBAAoB,SAAS,EAAE;AAClD,UAAM,gBACJ,IAAI,eAAe,IAAI,aAAa,IAAI,eAAe;AAEzD,QAAI,CAAC,iBAAiB,cAAc,UAAU,IAAI,WAAW;AAAA,IAE7D,OAAO;AACL,UAAI,eAAe;AACjB,+BAAuB,UAAU;AAAA,MACnC;AAEA,UAAI,kBAAkB,YAAY;AAChC,sBAAc,mBAAmB,EAAE,SAAS;AAAA,UAC1C,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AAEA,kBAAc,UAAU,IAAI;AAAA,EAC9B;AAEA,QAAM,YAAY,mBAAmB,MAAM;AACzC,QACE,uBAAuB,WACvB,oBAAoB,SAAS,EAAE,YAC/B;AACA,qBAAe,SAAS;AAAA,IAC1B;AAEA,iBAAa;AAAA,EACf,CAAC;AAED,QAAM,YAAY,cAA2B,CAAC,OAAO;AACnD,OAAG,iBAAiB,UAAU,YAAY;AAC1C,WAAO,MAAM;AACX,SAAG,oBAAoB,UAAU,YAAY;AAAA,IAC/C;AAAA,EACF,CAAC;AAED,sBAAoB,MAAM;AACxB,mBAAe,MAAM;AAAA,EACvB,CAAC;AAGD,QAAM,gBAAgB,iBAAiB;AACvC,YAAU,MAAM;AACd,WAAO,cAAc,YAAY,aAAa,MAAM,eAAe,MAAM,CAAC;AAAA,EAC5E,GAAG,CAAC,gBAAgB,aAAa,CAAC;AAElC,QAAM,gBAAgB,gBAA0B,WAAW,WAAW,MAAM;AAC5E,SAAO;AACT;","names":[]}