Upgrade Alias-Agent to 0.2.0 (#51)

Upgrade Alias-Agent to 0.2.0

---------

Co-authored-by: ZiTao-Li <zitao.l@alibaba-inc.com>
Co-authored-by: xieyxclack <yuexiang.xyx@alibaba-inc.com>
Co-authored-by: Zexi Li <tomleeze@qq.com>
Co-authored-by: SSSuperDan <dlaura2218@gmail.com>
Co-authored-by: lalaliat <78087788+lalaliat@users.noreply.github.com>
Co-authored-by: jinli.yl <jinli.yl@alibaba-inc.com>
Co-authored-by: Dengjiaji <dengjiaji.djj@alibaba-inc.com>
Co-authored-by: 于南 <zengtianjing.ztj@alibaba-inc.com>
Co-authored-by: JustinDing <166603159+sleepy-bird-world@users.noreply.github.com>
Co-authored-by: y1y5 <269557841@qq.com>
Co-authored-by: 柳佚 <yly287738@alibaba-inc.com>
Co-authored-by: LiangguiWeng <347185100@qq.com>
Co-authored-by: 潜星 <zhijian.mzj@alibaba-inc.com>
Co-authored-by: StCarmen <1106135234@qq.com>
Co-authored-by: LuYi <yilu_2000@outlook.com>
Co-authored-by: 刺葳 <ciwei.cy@alibaba-inc.com>
This commit is contained in:
Yue Cui
2025-12-03 20:58:25 +08:00
committed by GitHub
parent 8af2dc6477
commit cb87558efe
430 changed files with 49058 additions and 3471 deletions

View File

@@ -0,0 +1,54 @@
// Key stylesheet section
.scrollRoot {
position: relative;
height: 100%;
overflow: auto;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
// Hide scrollbar but keep scroll functionality
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
.scrollButton {
position: absolute;
right: 50%;
bottom: 20px;
z-index: 100;
width: 40px;
height: 40px;
border-radius: 50%;
border: none;
background: var(--scroll-button-bg);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
&:hover {
background: var(--scroll-button-bg-hover);
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.2);
transform: translateY(-1px);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -0,0 +1,117 @@
import { isAtBottom, isManualScrolling } from "@/utils/sharedRefs";
import React, {
forwardRef,
useCallback,
useImperativeHandle,
useRef,
useState,
} from "react";
import styles from "./index.module.scss";
// import { debounce } from "lodash";
interface ScrollToBottomButtonProps
extends React.HTMLAttributes<HTMLDivElement> {
autoScrollThreshold?: number;
}
interface ScrollToBottomButtonHandles {
scrollToBottom: (behavior?: ScrollBehavior) => void;
}
const ScrollToBottomButton = forwardRef<
ScrollToBottomButtonHandles,
ScrollToBottomButtonProps
>(({ children, autoScrollThreshold = 1, className, ...props }, ref) => {
const [showButton, setShowButton] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
const isScroll = useRef(false);
const isAutoScrolling = useRef<boolean>(false);
const scrollTimeout = useRef<NodeJS.Timeout | null>(null);
// Precise bottom detection
const checkIsAtBottom = useCallback(() => {
const container = containerRef.current;
if (!container) return true;
// const { scrollTop, scrollHeight, clientHeight } = container;
// Handle floating point precision: round to integer
const { scrollTop, scrollHeight, clientHeight } = container;
// Calculate difference from bottom and take absolute value
const diff = scrollHeight - (scrollTop + clientHeight);
const isBottom = Math.abs(diff) <= Math.max(30, autoScrollThreshold);
isAtBottom.current = isBottom;
return isAtBottom.current;
}, [autoScrollThreshold]);
// Scroll method with lock
const scrollToBottom = useCallback((behavior: ScrollBehavior = "smooth") => {
const container = containerRef.current;
if (!container) return;
// Clear previous timer
if (scrollTimeout.current) {
clearTimeout(scrollTimeout.current);
}
isScroll.current = false;
isAutoScrolling.current = true;
setShowButton(false);
// container.style.scrollBehavior = behavior;
container.scrollTop = container.scrollHeight;
container.style.scrollBehavior = "auto";
isAtBottom.current = true;
isManualScrolling.current = true;
// Set new timer
scrollTimeout.current = setTimeout(() => {
if (container) {
isAutoScrolling.current = false;
// isManualScrolling.current = true;
}
// Clean up timer reference
scrollTimeout.current = null;
}, 0);
}, []);
// Optimized scroll handling
const handleScroll = useCallback(() => {
requestAnimationFrame(() => {
if (isAutoScrolling.current) return;
setShowButton(!checkIsAtBottom());
isScroll.current = !checkIsAtBottom();
isManualScrolling.current = false;
});
}, [checkIsAtBottom]);
useImperativeHandle(ref, () => ({
scrollToBottom,
checkIsAtBottom,
}));
return (
<div
{...props}
ref={containerRef}
className={`${styles.scrollRoot} ${className}`}
onScroll={handleScroll}
>
{children}
<div
className={styles.scrollAnchor}
style={{ position: "absolute", bottom: 0 }}
/>
{isScroll.current && showButton && (
<button
className={styles.scrollButton}
onClick={() => scrollToBottom("auto")}
style={{
position: "sticky",
bottom: "20px",
float: "right",
animation: `${styles.fadeIn} 0.3s forwards`,
}}
>
</button>
)}
</div>
);
});
export default ScrollToBottomButton;