mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Fix allow_focus
This commit is contained in:
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Fixed footer / key panel not updating when keymaps are applied https://github.com/Textualize/textual/pull/5724
|
||||
- Fixed alignment not being applied when there are min and max limits on dimensions https://github.com/Textualize/textual/pull/5732
|
||||
- Fixed issues with OptionList scrollbar not updating https://github.com/Textualize/textual/pull/5736
|
||||
- Fixed allow_focus method not overriding can_focus
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ class ChangingThemeApp(App[None]):
|
||||
widget.__class__.__name__,
|
||||
(
|
||||
partial(self.set_focus, widget)
|
||||
if widget.can_focus
|
||||
if widget.allow_focus()
|
||||
else lambda: None
|
||||
),
|
||||
f"Focus on {widget.__class__.__name__}",
|
||||
|
||||
@@ -378,7 +378,7 @@ class Widget(DOMNode):
|
||||
"hover": lambda widget: widget.mouse_hover,
|
||||
"focus": lambda widget: widget.has_focus,
|
||||
"blur": lambda widget: not widget.has_focus,
|
||||
"can-focus": lambda widget: widget.can_focus,
|
||||
"can-focus": lambda widget: widget.allow_focus(),
|
||||
"disabled": lambda widget: widget.is_disabled,
|
||||
"enabled": lambda widget: not widget.is_disabled,
|
||||
"dark": lambda widget: widget.app.current_theme.dark,
|
||||
|
||||
@@ -3894,6 +3894,7 @@ def test_notifications_markup(snap_compare):
|
||||
|
||||
assert snap_compare(ToastApp())
|
||||
|
||||
|
||||
def test_option_list_size_when_options_removed(snap_compare):
|
||||
"""Regression test for https://github.com/Textualize/textual/issues/5728
|
||||
|
||||
@@ -3935,6 +3936,7 @@ def test_option_list_size_when_options_cleared(snap_compare):
|
||||
|
||||
assert snap_compare(OptionListApp(), press=["x"])
|
||||
|
||||
|
||||
def test_alignment_with_auto_and_min_height(snap_compare):
|
||||
"""Regression test for https://github.com/Textualize/textual/issues/5608
|
||||
You should see a blue label that is centered both horizontally and vertically
|
||||
@@ -3962,3 +3964,41 @@ def test_alignment_with_auto_and_min_height(snap_compare):
|
||||
yield Label("centered")
|
||||
|
||||
assert snap_compare(AlignmentApp())
|
||||
|
||||
|
||||
def test_allow_focus(snap_compare):
|
||||
"""Regression test for https://github.com/Textualize/textual/issues/5609
|
||||
|
||||
You should see two placeholders split vertically.
|
||||
The top should have the label "FOCUSABLE", and have a heavy red border.
|
||||
The bottom should have the label "NON FOCUSABLE" and have the default border.
|
||||
"""
|
||||
|
||||
class Focusable(Placeholder, can_focus=False):
|
||||
"""Override can_focus from False to True"""
|
||||
|
||||
def allow_focus(self) -> bool:
|
||||
return True
|
||||
|
||||
class NonFocusable(Placeholder, can_focus=True):
|
||||
"""Override can_focus from True to False"""
|
||||
|
||||
def allow_focus(self) -> bool:
|
||||
return False
|
||||
|
||||
class FocusApp(App):
|
||||
CSS = """
|
||||
Placeholder {
|
||||
height: 1fr;
|
||||
}
|
||||
*:can-focus {
|
||||
border: heavy red;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Focusable("FOCUSABLE")
|
||||
yield NonFocusable("NON FOCUSABLE")
|
||||
|
||||
assert snap_compare(FocusApp())
|
||||
|
||||
@@ -2,6 +2,7 @@ from textual.app import App, ComposeResult
|
||||
from textual.containers import Container, ScrollableContainer
|
||||
from textual.widget import Widget
|
||||
from textual.widgets import Button, Label
|
||||
from textual.widgets._placeholder import Placeholder
|
||||
|
||||
|
||||
class Focusable(Widget, can_focus=True):
|
||||
@@ -464,3 +465,45 @@ async def test_get_focusable_widget_at() -> None:
|
||||
await pilot.click("#egg")
|
||||
# Confirm nothing focused
|
||||
assert app.screen.focused is None
|
||||
|
||||
|
||||
async def test_allow_focus_override():
|
||||
"""Test that allow_focus() method override can_focus."""
|
||||
|
||||
class Focusable(Placeholder, can_focus=False):
|
||||
"""Override can_focus from False to True"""
|
||||
|
||||
def allow_focus(self) -> bool:
|
||||
return True
|
||||
|
||||
class NonFocusable(Placeholder, can_focus=True):
|
||||
"""Override can_focus from True to False"""
|
||||
|
||||
def allow_focus(self) -> bool:
|
||||
return False
|
||||
|
||||
class FocusApp(App):
|
||||
CSS = """
|
||||
Placeholder {
|
||||
height: 1fr;
|
||||
}
|
||||
*:can-focus {
|
||||
border: heavy red;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Focusable("FOCUSABLE")
|
||||
yield NonFocusable("NON FOCUSABLE")
|
||||
|
||||
app = FocusApp()
|
||||
async with app.run_test():
|
||||
# Default should be focused
|
||||
assert isinstance(app.focused, Focusable)
|
||||
# Attempt to focus non focusable
|
||||
app.query(NonFocusable).focus()
|
||||
# Unable to focus NonFocusable
|
||||
assert isinstance(app.focused, Focusable)
|
||||
# Check focus chain
|
||||
assert app.screen.focus_chain == [app.query_one(Focusable)]
|
||||
|
||||
Reference in New Issue
Block a user