|
2 | 2 | from textual.containers import Container, ScrollableContainer
|
3 | 3 | from textual.widget import Widget
|
4 | 4 | from textual.widgets import Button, Label
|
| 5 | +from textual.widgets._placeholder import Placeholder |
5 | 6 |
|
6 | 7 |
|
7 | 8 | class Focusable(Widget, can_focus=True):
|
@@ -464,3 +465,45 @@ def compose(self) -> ComposeResult:
|
464 | 465 | await pilot.click("#egg")
|
465 | 466 | # Confirm nothing focused
|
466 | 467 | assert app.screen.focused is None
|
| 468 | + |
| 469 | + |
| 470 | +async def test_allow_focus_override(): |
| 471 | + """Test that allow_focus() method override can_focus.""" |
| 472 | + |
| 473 | + class Focusable(Placeholder, can_focus=False): |
| 474 | + """Override can_focus from False to True""" |
| 475 | + |
| 476 | + def allow_focus(self) -> bool: |
| 477 | + return True |
| 478 | + |
| 479 | + class NonFocusable(Placeholder, can_focus=True): |
| 480 | + """Override can_focus from True to False""" |
| 481 | + |
| 482 | + def allow_focus(self) -> bool: |
| 483 | + return False |
| 484 | + |
| 485 | + class FocusApp(App): |
| 486 | + CSS = """ |
| 487 | + Placeholder { |
| 488 | + height: 1fr; |
| 489 | + } |
| 490 | + *:can-focus { |
| 491 | + border: heavy red; |
| 492 | + } |
| 493 | +
|
| 494 | + """ |
| 495 | + |
| 496 | + def compose(self) -> ComposeResult: |
| 497 | + yield Focusable("FOCUSABLE") |
| 498 | + yield NonFocusable("NON FOCUSABLE") |
| 499 | + |
| 500 | + app = FocusApp() |
| 501 | + async with app.run_test(): |
| 502 | + # Default should be focused |
| 503 | + assert isinstance(app.focused, Focusable) |
| 504 | + # Attempt to focus non focusable |
| 505 | + app.query(NonFocusable).focus() |
| 506 | + # Unable to focus NonFocusable |
| 507 | + assert isinstance(app.focused, Focusable) |
| 508 | + # Check focus chain |
| 509 | + assert app.screen.focus_chain == [app.query_one(Focusable)] |
0 commit comments