Source code for duck.html.components.progressbar
"""
Progress bar component.
"""
from duck.html.components.container import Container
from duck.html.components.script import Script
PROGRESS_BAR_SCRIPT = """
function updateProgressBar(progressBar, progress, autoHideWhenZero = true) {{
const progressBarInner = progressBar.querySelector('.progress-bar-inner');
progress = Math.max(0, Math.min(100, progress));
requestAnimationFrame(() => {{
if (!progressBarInner) return;
if (progress > 0) {{
progressBar.style.display = 'inline-block';
progressBarInner.style.transform = `scaleX(${{progress / 100}})`;
}} else if (autoHideWhenZero) {{
hideProgressBar(progressBar, false);
}} else {{
progressBarInner.style.transform = 'scaleX(0)';
}}
}});
}}
function hideProgressBar(progressBar, nextAnimationFrame = true) {{
const progressBarInner = progressBar.querySelector('.progress-bar-inner');
const applyHiddenState = () => {{
progressBar.style.display = 'none';
if (progressBarInner) {{
progressBarInner.style.transform = 'scaleX(0)';
}}
}};
if (nextAnimationFrame) {{
requestAnimationFrame(applyHiddenState);
return;
}}
applyHiddenState();
}}
"""
[docs]
class ProgressBar(Container):
"""
Modern loading bar with JavaScript and Python update helpers.
"""
[docs]
def on_create(self) -> None:
"""
Initialize and compose the progress bar.
"""
super().on_create()
# Component setup
self.bg_color = "rgba(0, 0, 0, .1)"
self.props.setdefault("id", "progress-bar")
self.style.update({
"width": "100%",
"height": "3px",
"border-radius": "3px",
"overflow": "hidden",
"display": "none",
"transition": "display 0.1s ease",
})
# Component children
self._progress_bar = Container(
klass="progress-bar-inner",
bg_color="#F5C842",
style={
"width": "100%",
"height": "100%",
"transition": "transform 0.1s ease",
"will-change": "transform",
"transform-origin": "left",
"transform": "scaleX(0)",
},
)
self.add_children([
self._progress_bar,
Script(inner_html=PROGRESS_BAR_SCRIPT.format(progress_bar_id=self.id)),
])
# Public API
[docs]
def update_progress(self, progress: int) -> None:
"""
Update the progress bar from Python.
Args:
progress: Progress percentage between ``0`` and ``100``.
Raises:
TypeError: If progress is not an integer.
ValueError: If progress is outside ``0`` to ``100``.
"""
if not isinstance(progress, int):
raise TypeError("Progress must be an integer.")
if not 0 <= progress <= 100:
raise ValueError("Progress must be between 0 and 100.")
self.style["display"] = "inline-block" if progress > 0 else "none"
self._progress_bar.style["transform"] = f"scaleX({progress / 100})"
[docs]
def set_progress_color(self, color: str) -> None:
"""
Set the filled progress indicator color.
Args:
color: CSS color value.
"""
self._progress_bar.bg_color = color
[docs]
def set_track_color(self, color: str) -> None:
"""
Set the progress track/background color.
Args:
color: CSS color value.
"""
self.bg_color = color