fix(tui): guard Throbber DOM queries against unmounted state

This commit is contained in:
2026-03-12 05:06:16 +00:00
parent a5361a93ae
commit 7dce78cd39
+11 -2
View File
@@ -13,6 +13,7 @@ import random
from enum import Enum
from textual.app import ComposeResult
from textual.css.query import NoMatches
from textual.reactive import reactive
from textual.timer import Timer
from textual.widget import Widget
@@ -95,6 +96,8 @@ class Throbber(Widget):
def _start_animation(self) -> None:
self._stop_animation()
if not self.is_mounted:
return
try:
if self.style_mode == ThrobberStyle.RAINBOW:
self._timer = self.set_interval(_RAINBOW_FPS, self._tick_rainbow)
@@ -117,6 +120,10 @@ class Throbber(Widget):
def _tick_rainbow(self) -> None:
"""Advance the rainbow gradient by one step."""
try:
content = self.query_one("#throbber-content", Static)
except NoMatches:
return
width = self.size.width or 40
gradient_len = len(RAINBOW_GRADIENT)
segments: list[str] = []
@@ -124,7 +131,6 @@ class Throbber(Widget):
color_idx = (i + self._offset) % gradient_len
color = RAINBOW_GRADIENT[color_idx]
segments.append(f"[{color}]{_GRADIENT_CHAR}[/]")
content = self.query_one("#throbber-content", Static)
content.update("".join(segments))
self._offset += 1
@@ -132,9 +138,12 @@ class Throbber(Widget):
"""Display the next loading quote."""
if not self._shuffled_quotes:
return
try:
content = self.query_one("#throbber-content", Static)
except NoMatches:
return
self._current_quote = self._shuffled_quotes[
self._quote_index % len(self._shuffled_quotes)
]
self._quote_index += 1
content = self.query_one("#throbber-content", Static)
content.update(f"[italic]{self._current_quote}[/italic]")