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:
@@ -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);
|
||||
}
|
||||
}
|
||||
117
alias/frontend/src/components/ScrollToBottomButton/index.tsx
Normal file
117
alias/frontend/src/components/ScrollToBottomButton/index.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user