mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Tabbed content activated message (#2260)
* Add a message for the tabbed content activated * Add a docstring * Testing tabbed content activated message * Update changelog * Add reference to the docs about TabbedContent.TabActivated
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
- Added `DataTable.remove_row` method https://github.com/Textualize/textual/pull/2253
|
||||
- `Widget.scroll_to_center` now scrolls the widget to the center of the screen https://github.com/Textualize/textual/pull/2255
|
||||
- Added `TabActivated` message to `TabbedContent` https://github.com/Textualize/textual/pull/2260
|
||||
|
||||
## [0.19.1] - 2023-04-10
|
||||
|
||||
|
||||
@@ -101,6 +101,10 @@ The following example contains a `TabbedContent` with three tabs.
|
||||
| `active` | `str` | `""` | The `id` attribute of the active tab. Set this to switch tabs. |
|
||||
|
||||
|
||||
## Messages
|
||||
|
||||
- [TabbedContent.TabActivated][textual.widgets.TabbedContent.TabActivated]
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ The following example adds a `Tabs` widget above a text label. Press ++a++ to ad
|
||||
|
||||
## Messages
|
||||
|
||||
- [Tabs.TabActivate][textual.widgets.Tabs.TabActivated]
|
||||
- [Tabs.TabActivated][textual.widgets.Tabs.TabActivated]
|
||||
- [Tabs.Cleared][textual.widgets.Tabs.Cleared]
|
||||
|
||||
## Bindings
|
||||
|
||||
@@ -2,9 +2,11 @@ from __future__ import annotations
|
||||
|
||||
from itertools import zip_longest
|
||||
|
||||
from rich.repr import Result
|
||||
from rich.text import Text, TextType
|
||||
|
||||
from ..app import ComposeResult
|
||||
from ..message import Message
|
||||
from ..reactive import reactive
|
||||
from ..widget import Widget
|
||||
from ._content_switcher import ContentSwitcher
|
||||
@@ -84,6 +86,24 @@ class TabbedContent(Widget):
|
||||
active: reactive[str] = reactive("", init=False)
|
||||
"""The ID of the active tab, or empty string if none are active."""
|
||||
|
||||
class TabActivated(Message):
|
||||
"""Posted when the active tab changes."""
|
||||
|
||||
def __init__(self, tabbed_content: TabbedContent, tab: Tab) -> None:
|
||||
"""Initialize message.
|
||||
|
||||
Args:
|
||||
tabbed_content: The TabbedContent widget.
|
||||
tab: The Tab widget that was selected (contains the tab label).
|
||||
"""
|
||||
self.tabbed_content = tabbed_content
|
||||
self.tab = tab
|
||||
super().__init__()
|
||||
|
||||
def __rich_repr__(self) -> Result:
|
||||
yield self.tabbed_content
|
||||
yield self.tab
|
||||
|
||||
def __init__(self, *titles: TextType, initial: str = "") -> None:
|
||||
"""Initialize a TabbedContent widgets.
|
||||
|
||||
@@ -167,6 +187,12 @@ class TabbedContent(Widget):
|
||||
assert isinstance(event.tab, ContentTab)
|
||||
switcher.current = event.tab.id
|
||||
self.active = event.tab.id
|
||||
self.post_message(
|
||||
TabbedContent.TabActivated(
|
||||
tabbed_content=self,
|
||||
tab=event.tab,
|
||||
)
|
||||
)
|
||||
|
||||
def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:
|
||||
"""All tabs were removed."""
|
||||
|
||||
@@ -14,7 +14,7 @@ async def test_tabbed_content_switch():
|
||||
yield Label("Foo", id="foo-label")
|
||||
with TabPane("bar", id="bar"):
|
||||
yield Label("Bar", id="bar-label")
|
||||
with TabPane("baz`", id="baz"):
|
||||
with TabPane("baz", id="baz"):
|
||||
yield Label("Baz", id="baz-label")
|
||||
|
||||
app = TabbedApp()
|
||||
@@ -73,11 +73,11 @@ async def test_tabbed_content_initial():
|
||||
yield Label("Foo", id="foo-label")
|
||||
with TabPane("bar", id="bar"):
|
||||
yield Label("Bar", id="bar-label")
|
||||
with TabPane("baz`", id="baz"):
|
||||
with TabPane("baz", id="baz"):
|
||||
yield Label("Baz", id="baz-label")
|
||||
|
||||
app = TabbedApp()
|
||||
async with app.run_test() as pilot:
|
||||
async with app.run_test():
|
||||
tabbed_content = app.query_one(TabbedContent)
|
||||
assert tabbed_content.active == "bar"
|
||||
|
||||
@@ -85,3 +85,31 @@ async def test_tabbed_content_initial():
|
||||
assert not app.query_one("#foo-label").region
|
||||
assert app.query_one("#bar-label").region
|
||||
assert not app.query_one("#baz-label").region
|
||||
|
||||
|
||||
async def test_tabbed_content_messages():
|
||||
class TabbedApp(App):
|
||||
message = None
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with TabbedContent(initial="bar"):
|
||||
with TabPane("foo", id="foo"):
|
||||
yield Label("Foo", id="foo-label")
|
||||
|
||||
with TabPane("bar", id="bar"):
|
||||
yield Label("Bar", id="bar-label")
|
||||
with TabPane("baz", id="baz"):
|
||||
yield Label("Baz", id="baz-label")
|
||||
|
||||
def on_tabbed_content_tab_activated(
|
||||
self, event: TabbedContent.TabActivated
|
||||
) -> None:
|
||||
self.message = event
|
||||
|
||||
app = TabbedApp()
|
||||
async with app.run_test() as pilot:
|
||||
tabbed_content = app.query_one(TabbedContent)
|
||||
tabbed_content.active = "bar"
|
||||
await pilot.pause()
|
||||
assert isinstance(app.message, TabbedContent.TabActivated)
|
||||
assert app.message.tab.label.plain == "bar"
|
||||
|
||||
Reference in New Issue
Block a user