add auto_scroll
This commit is contained in:
parent
8b2c7291d3
commit
7b9c584b5b
reflex/components/core
@ -48,6 +48,7 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
||||
"get_upload_url",
|
||||
"selected_files",
|
||||
],
|
||||
"auto_scroll": ["auto_scroll"],
|
||||
}
|
||||
|
||||
__getattr__, __dir__, __all__ = lazy_loader.attach(
|
||||
|
@ -4,6 +4,7 @@
|
||||
# ------------------------------------------------------
|
||||
|
||||
from . import layout as layout
|
||||
from .auto_scroll import auto_scroll as auto_scroll
|
||||
from .banner import ConnectionBanner as ConnectionBanner
|
||||
from .banner import ConnectionModal as ConnectionModal
|
||||
from .banner import ConnectionPulser as ConnectionPulser
|
||||
|
110
reflex/components/core/auto_scroll.py
Normal file
110
reflex/components/core/auto_scroll.py
Normal file
@ -0,0 +1,110 @@
|
||||
"""A component that automatically scrolls to the bottom when new content is added."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from reflex.components.el.elements.typography import Div
|
||||
from reflex.constants.compiler import MemoizationDisposition, MemoizationMode
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class AutoScroll(Div):
|
||||
"""A div that automatically scrolls to the bottom when new content is added."""
|
||||
|
||||
_memoization_mode = MemoizationMode(disposition=MemoizationDisposition.ALWAYS)
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props):
|
||||
"""Create an AutoScroll component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
An AutoScroll component.
|
||||
"""
|
||||
props.setdefault("overflow", "auto")
|
||||
custom_attrs = props.pop("custom_attrs", {})
|
||||
custom_attrs["ref"] = Var("containerRef")
|
||||
return super().create(*children, **props, custom_attrs=custom_attrs)
|
||||
|
||||
def add_imports(self) -> ImportDict | list[ImportDict]:
|
||||
"""Add imports required for the component.
|
||||
|
||||
Returns:
|
||||
The imports required for the component.
|
||||
"""
|
||||
return {"react": ["useEffect", "useRef"]}
|
||||
|
||||
def add_hooks(self) -> list[str | Var]:
|
||||
"""Add hooks required for the component.
|
||||
|
||||
Returns:
|
||||
The hooks required for the component.
|
||||
"""
|
||||
return [
|
||||
"const containerRef = useRef(null);",
|
||||
"const wasNearBottom = useRef(false);",
|
||||
"const hadScrollbar = useRef(false);",
|
||||
"""
|
||||
const checkIfNearBottom = () => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const container = containerRef.current;
|
||||
const nearBottomThreshold = 50; // pixels from bottom to trigger auto-scroll
|
||||
|
||||
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
|
||||
|
||||
wasNearBottom.current = distanceFromBottom <= nearBottomThreshold;
|
||||
|
||||
// Track if container had a scrollbar
|
||||
hadScrollbar.current = container.scrollHeight > container.clientHeight;
|
||||
};
|
||||
""",
|
||||
"""
|
||||
const scrollToBottomIfNeeded = () => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const container = containerRef.current;
|
||||
const hasScrollbarNow = container.scrollHeight > container.clientHeight;
|
||||
|
||||
// Scroll if:
|
||||
// 1. User was near bottom, OR
|
||||
// 2. Container didn't have scrollbar before but does now
|
||||
if (wasNearBottom.current || (!hadScrollbar.current && hasScrollbarNow)) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
// Update scrollbar state for next check
|
||||
hadScrollbar.current = hasScrollbarNow;};
|
||||
""",
|
||||
"""
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
// Create ResizeObserver to detect height changes
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
scrollToBottomIfNeeded();
|
||||
});
|
||||
|
||||
// Track scroll position before height changes
|
||||
container.addEventListener('scroll', checkIfNearBottom);
|
||||
|
||||
// Initial check
|
||||
checkIfNearBottom();
|
||||
|
||||
// Observe container for size changes
|
||||
resizeObserver.observe(container);
|
||||
|
||||
return () => {
|
||||
container.removeEventListener('scroll', checkIfNearBottom);
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
});
|
||||
""",
|
||||
]
|
||||
|
||||
|
||||
auto_scroll = AutoScroll.create
|
Loading…
Reference in New Issue
Block a user