mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge pull request #1854 from Textualize/css-fix-virtual-class
WIP Css fix virtual class
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
42
tests/snapshot_tests/snapshot_apps/focus_component_class.py
Normal file
42
tests/snapshot_tests/snapshot_apps/focus_component_class.py
Normal 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()
|
||||
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user