use random id for maximum safety

This commit is contained in:
Khaleel Al-Adhami 2025-02-12 11:29:28 -08:00
parent 7841e27d32
commit de183bf42c

View File

@ -5,7 +5,7 @@ from __future__ import annotations
from reflex.components.el.elements.typography import Div from reflex.components.el.elements.typography import Div
from reflex.constants.compiler import MemoizationDisposition, MemoizationMode from reflex.constants.compiler import MemoizationDisposition, MemoizationMode
from reflex.utils.imports import ImportDict from reflex.utils.imports import ImportDict
from reflex.vars.base import Var from reflex.vars.base import Var, get_unique_variable_name
class AutoScroll(Div): class AutoScroll(Div):
@ -25,9 +25,8 @@ class AutoScroll(Div):
An AutoScroll component. An AutoScroll component.
""" """
props.setdefault("overflow", "auto") props.setdefault("overflow", "auto")
custom_attrs = props.pop("custom_attrs", {}) props.setdefault("id", get_unique_variable_name())
custom_attrs["ref"] = Var("containerRef") return super().create(*children, **props)
return super().create(*children, **props, custom_attrs=custom_attrs)
def add_imports(self) -> ImportDict | list[ImportDict]: def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports required for the component. """Add imports required for the component.
@ -43,15 +42,16 @@ class AutoScroll(Div):
Returns: Returns:
The hooks required for the component. The hooks required for the component.
""" """
ref_name = self.get_ref()
return [ return [
"const containerRef = useRef(null);", "const containerRef = useRef(null);",
"const wasNearBottom = useRef(false);", "const wasNearBottom = useRef(false);",
"const hadScrollbar = useRef(false);", "const hadScrollbar = useRef(false);",
""" f"""
const checkIfNearBottom = () => { const checkIfNearBottom = () => {{
if (!containerRef.current) return; if (!{ref_name}.current) return;
const container = containerRef.current; const container = {ref_name}.current;
const nearBottomThreshold = 50; // pixels from bottom to trigger auto-scroll const nearBottomThreshold = 50; // pixels from bottom to trigger auto-scroll
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight; const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
@ -60,34 +60,35 @@ const checkIfNearBottom = () => {
// Track if container had a scrollbar // Track if container had a scrollbar
hadScrollbar.current = container.scrollHeight > container.clientHeight; hadScrollbar.current = container.scrollHeight > container.clientHeight;
}; }};
""", """,
""" f"""
const scrollToBottomIfNeeded = () => { const scrollToBottomIfNeeded = () => {{
if (!containerRef.current) return; if (!{ref_name}.current) return;
const container = containerRef.current; const container = {ref_name}.current;
const hasScrollbarNow = container.scrollHeight > container.clientHeight; const hasScrollbarNow = container.scrollHeight > container.clientHeight;
// Scroll if: // Scroll if:
// 1. User was near bottom, OR // 1. User was near bottom, OR
// 2. Container didn't have scrollbar before but does now // 2. Container didn't have scrollbar before but does now
if (wasNearBottom.current || (!hadScrollbar.current && hasScrollbarNow)) { if (wasNearBottom.current || (!hadScrollbar.current && hasScrollbarNow)) {{
container.scrollTop = container.scrollHeight; container.scrollTop = container.scrollHeight;
} }}
// Update scrollbar state for next check // Update scrollbar state for next check
hadScrollbar.current = hasScrollbarNow;}; hadScrollbar.current = hasScrollbarNow;
}};
""", """,
""" f"""
useEffect(() => { useEffect(() => {{
const container = containerRef.current; const container = {ref_name}.current;
if (!container) return; if (!container) return;
// Create ResizeObserver to detect height changes // Create ResizeObserver to detect height changes
const resizeObserver = new ResizeObserver(() => { const resizeObserver = new ResizeObserver(() => {{
scrollToBottomIfNeeded(); scrollToBottomIfNeeded();
}); }});
// Track scroll position before height changes // Track scroll position before height changes
container.addEventListener('scroll', checkIfNearBottom); container.addEventListener('scroll', checkIfNearBottom);
@ -98,11 +99,11 @@ const scrollToBottomIfNeeded = () => {
// Observe container for size changes // Observe container for size changes
resizeObserver.observe(container); resizeObserver.observe(container);
return () => { return () => {{
container.removeEventListener('scroll', checkIfNearBottom); container.removeEventListener('scroll', checkIfNearBottom);
resizeObserver.disconnect(); resizeObserver.disconnect();
}; }};
}); }});
""", """,
] ]