Merge pull request #1854 from Textualize/css-fix-virtual-class

WIP Css fix virtual class
This commit is contained in:
Will McGugan
2023-02-22 16:01:48 +00:00
committed by GitHub
5 changed files with 233 additions and 7 deletions

View File

@@ -969,9 +969,17 @@ class RenderStyles(StylesBase):
self._rich_style: tuple[int, Style] | None = None
self._gutter: tuple[int, Spacing] | None = None
def __eq__(self, other: object) -> bool:
if isinstance(other, RenderStyles):
return (
self._base_styles._rules == other._base_styles._rules
and self._inline_styles._rules == other._inline_styles._rules
)
return NotImplemented
@property
def _cache_key(self) -> int:
"""A key key, that changes when any style is changed.
"""A cache key, that changes when any style is changed.
Returns:
An opaque integer.

View File

@@ -406,12 +406,25 @@ class Stylesheet:
)
self.replace_rules(node, node_rules, animate=animate)
node._component_styles.clear()
for component in node._get_component_classes():
virtual_node = DOMNode(classes=component)
virtual_node._attach(node)
self.apply(virtual_node, animate=False)
node._component_styles[component] = virtual_node.styles
component_classes = node._get_component_classes()
if component_classes:
# Create virtual nodes that exist to extract styles
refresh_node = False
old_component_styles = node._component_styles.copy()
node._component_styles.clear()
for component in sorted(component_classes):
virtual_node = DOMNode(classes=component)
virtual_node._attach(node)
self.apply(virtual_node, animate=False)
if (
not refresh_node
and old_component_styles.get(component) != virtual_node.styles
):
# If the styles have changed we want to refresh the node
refresh_node = True
node._component_styles[component] = virtual_node.styles
if refresh_node:
node.refresh()
@classmethod
def replace_rules(

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
from rich.text import Text
from textual.app import App, ComposeResult, RenderResult
from textual.containers import Vertical
from textual.widgets import Header, Footer
from textual.widget import Widget
class Tester(Widget, can_focus=True):
COMPONENT_CLASSES = {"tester--text"}
DEFAULT_CSS = """
Tester {
height: auto;
}
Tester:focus > .tester--text {
background: red;
}
"""
def __init__(self, n: int) -> None:
self.n = n
super().__init__()
def render(self) -> RenderResult:
return Text(
f"test widget {self.n}", style=self.get_component_rich_style("tester--text")
)
class StyleBugApp(App[None]):
def compose(self) -> ComposeResult:
yield Header()
with Vertical():
for n in range(40):
yield Tester(n)
yield Footer()
if __name__ == "__main__":
StyleBugApp().run()

View File

@@ -235,3 +235,7 @@ def test_screen_switch(snap_compare):
def test_disabled_widgets(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "disable_widgets.py")
def test_focus_component_class(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "focus_component_class.py", press=["tab"])