From c667c861071b094c50ecb0025babc518a36ec529 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 7 Nov 2023 16:22:40 +0000 Subject: [PATCH] Blur (#3645) * added blur * add blur pseudo class * added blur psuedo class * added test --- CHANGELOG.md | 1 + docs/guide/CSS.md | 1 + src/textual/widget.py | 2 ++ tests/test_app.py | 15 +++++++++++++-- tests/test_focus.py | 30 +++++++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b32ed2b1..4b04363b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Duplicate CSS errors when parsing CSS from a screen https://github.com/Textualize/textual/issues/3581 +- Added missing `blur` pseudo class https://github.com/Textualize/textual/issues/3439 - Fixed visual glitched characters on Windows due to Python limitation https://github.com/Textualize/textual/issues/2548 ### Changed diff --git a/docs/guide/CSS.md b/docs/guide/CSS.md index 7365f0b094..9dd18155f1 100644 --- a/docs/guide/CSS.md +++ b/docs/guide/CSS.md @@ -324,6 +324,7 @@ Here are some other pseudo classes: - `:disabled` Matches widgets which are in a disabled state. - `:enabled` Matches widgets which are in an enabled state. - `:focus` Matches widgets which have input focus. +- `:blur` Matches widgets which *do not* have input focus. - `:focus-within` Matches widgets with a focused child widget. - `:dark` Matches widgets in dark mode (where `App.dark == True`). - `:light` Matches widgets in dark mode (where `App.dark == False`). diff --git a/src/textual/widget.py b/src/textual/widget.py index 005fdf14d2..2d4dcd3ec9 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -2779,6 +2779,8 @@ def get_pseudo_classes(self) -> Iterable[str]: yield "hover" if self.has_focus: yield "focus" + else: + yield "blur" if self.can_focus: yield "can-focus" try: diff --git a/tests/test_app.py b/tests/test_app.py index 1fe20a46a4..e5afed1e2a 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -30,14 +30,25 @@ async def test_hover_update_styles(): app = MyApp() async with app.run_test() as pilot: button = app.query_one(Button) - assert button.pseudo_classes == {"enabled", "can-focus", "dark"} + assert button.pseudo_classes == { + "blur", + "can-focus", + "dark", + "enabled", + } # Take note of the initial background colour initial_background = button.styles.background await pilot.hover(Button) # We've hovered, so ensure the pseudoclass is present and background changed - assert button.pseudo_classes == {"enabled", "hover", "can-focus", "dark"} + assert button.pseudo_classes == { + "blur", + "can-focus", + "dark", + "enabled", + "hover", + } assert button.styles.background != initial_background diff --git a/tests/test_focus.py b/tests/test_focus.py index 489d808c26..486356bfe0 100644 --- a/tests/test_focus.py +++ b/tests/test_focus.py @@ -1,6 +1,6 @@ import pytest -from textual.app import App +from textual.app import App, ComposeResult from textual.containers import Container from textual.screen import Screen from textual.widget import Widget @@ -309,3 +309,31 @@ def compose(self): w11, w12, ] + + +async def test_focus_pseudo_class(): + """Test focus and blue pseudo classes""" + + # https://github.com/Textualize/textual/pull/3645 + class FocusApp(App): + AUTO_FOCUS = None + + def compose(self) -> ComposeResult: + yield Button("Hello") + + app = FocusApp() + async with app.run_test() as pilot: + button = app.query_one(Button) + classes = list(button.get_pseudo_classes()) + # Blurred, not focused + assert "blur" in classes + assert "focus" not in classes + + # Focus the button + button.focus() + await pilot.pause() + + # Focused, not blurred + classes = list(button.get_pseudo_classes()) + assert "blur" not in classes + assert "focus" in classes