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
|
- 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
|
- `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
|
## [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. |
|
| `active` | `str` | `""` | The `id` attribute of the active tab. Set this to switch tabs. |
|
||||||
|
|
||||||
|
|
||||||
|
## Messages
|
||||||
|
|
||||||
|
- [TabbedContent.TabActivated][textual.widgets.TabbedContent.TabActivated]
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ The following example adds a `Tabs` widget above a text label. Press ++a++ to ad
|
|||||||
|
|
||||||
## Messages
|
## Messages
|
||||||
|
|
||||||
- [Tabs.TabActivate][textual.widgets.Tabs.TabActivated]
|
- [Tabs.TabActivated][textual.widgets.Tabs.TabActivated]
|
||||||
- [Tabs.Cleared][textual.widgets.Tabs.Cleared]
|
- [Tabs.Cleared][textual.widgets.Tabs.Cleared]
|
||||||
|
|
||||||
## Bindings
|
## Bindings
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
|
|
||||||
|
from rich.repr import Result
|
||||||
from rich.text import Text, TextType
|
from rich.text import Text, TextType
|
||||||
|
|
||||||
from ..app import ComposeResult
|
from ..app import ComposeResult
|
||||||
|
from ..message import Message
|
||||||
from ..reactive import reactive
|
from ..reactive import reactive
|
||||||
from ..widget import Widget
|
from ..widget import Widget
|
||||||
from ._content_switcher import ContentSwitcher
|
from ._content_switcher import ContentSwitcher
|
||||||
@@ -84,6 +86,24 @@ class TabbedContent(Widget):
|
|||||||
active: reactive[str] = reactive("", init=False)
|
active: reactive[str] = reactive("", init=False)
|
||||||
"""The ID of the active tab, or empty string if none are active."""
|
"""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:
|
def __init__(self, *titles: TextType, initial: str = "") -> None:
|
||||||
"""Initialize a TabbedContent widgets.
|
"""Initialize a TabbedContent widgets.
|
||||||
|
|
||||||
@@ -167,6 +187,12 @@ class TabbedContent(Widget):
|
|||||||
assert isinstance(event.tab, ContentTab)
|
assert isinstance(event.tab, ContentTab)
|
||||||
switcher.current = event.tab.id
|
switcher.current = event.tab.id
|
||||||
self.active = 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:
|
def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:
|
||||||
"""All tabs were removed."""
|
"""All tabs were removed."""
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ async def test_tabbed_content_switch():
|
|||||||
yield Label("Foo", id="foo-label")
|
yield Label("Foo", id="foo-label")
|
||||||
with TabPane("bar", id="bar"):
|
with TabPane("bar", id="bar"):
|
||||||
yield Label("Bar", id="bar-label")
|
yield Label("Bar", id="bar-label")
|
||||||
with TabPane("baz`", id="baz"):
|
with TabPane("baz", id="baz"):
|
||||||
yield Label("Baz", id="baz-label")
|
yield Label("Baz", id="baz-label")
|
||||||
|
|
||||||
app = TabbedApp()
|
app = TabbedApp()
|
||||||
@@ -73,11 +73,11 @@ async def test_tabbed_content_initial():
|
|||||||
yield Label("Foo", id="foo-label")
|
yield Label("Foo", id="foo-label")
|
||||||
with TabPane("bar", id="bar"):
|
with TabPane("bar", id="bar"):
|
||||||
yield Label("Bar", id="bar-label")
|
yield Label("Bar", id="bar-label")
|
||||||
with TabPane("baz`", id="baz"):
|
with TabPane("baz", id="baz"):
|
||||||
yield Label("Baz", id="baz-label")
|
yield Label("Baz", id="baz-label")
|
||||||
|
|
||||||
app = TabbedApp()
|
app = TabbedApp()
|
||||||
async with app.run_test() as pilot:
|
async with app.run_test():
|
||||||
tabbed_content = app.query_one(TabbedContent)
|
tabbed_content = app.query_one(TabbedContent)
|
||||||
assert tabbed_content.active == "bar"
|
assert tabbed_content.active == "bar"
|
||||||
|
|
||||||
@@ -85,3 +85,31 @@ async def test_tabbed_content_initial():
|
|||||||
assert not app.query_one("#foo-label").region
|
assert not app.query_one("#foo-label").region
|
||||||
assert app.query_one("#bar-label").region
|
assert app.query_one("#bar-label").region
|
||||||
assert not app.query_one("#baz-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