Skip to content

Commit

Permalink
feat(collapsible): make title a reactive attribute (#3830)
Browse files Browse the repository at this point in the history
* feat(collapsible): make title a reactive attribute

* update docs and changelog

* fix collapsed in init

* change collapsible title to static

* remove unnecessary mounted check
  • Loading branch information
TomJGooding authored Dec 15, 2023
1 parent bf7b70c commit e72bab3
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Added `get_loading_widget` to Widget and App customize the loading widget. https://github.com/Textualize/textual/pull/3816
- Added messages `Collapsible.Expanded` and `Collapsible.Collapsed` that inherit from `Collapsible.Toggled`. https://github.com/Textualize/textual/issues/3824
- Added `Collapsible.title` reactive attribute https://github.com/Textualize/textual/pull/3830

## [0.44.1] - 2023-12-4

Expand Down
7 changes: 4 additions & 3 deletions docs/widgets/collapsible.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ The following example shows `Collapsible` widgets with custom expand/collapse sy

## Reactive Attributes

| Name | Type | Default | Description |
| ----------- | ------ | ------- | ---------------------------------------------------- |
| `collapsed` | `bool` | `True` | Controls the collapsed/expanded state of the widget. |
| Name | Type | Default | Description |
| ----------- | ------ | ------------| ---------------------------------------------------- |
| `collapsed` | `bool` | `True` | Controls the collapsed/expanded state of the widget. |
| `title` | `str` | `"Toggle"` | Title of the collapsed/expanded contents. |

## Messages

Expand Down
33 changes: 23 additions & 10 deletions src/textual/widgets/_collapsible.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from __future__ import annotations

from rich.console import RenderableType
from rich.text import Text

from .. import events
from ..app import ComposeResult
from ..binding import Binding
Expand All @@ -11,11 +8,12 @@
from ..message import Message
from ..reactive import reactive
from ..widget import Widget
from ..widgets import Static

__all__ = ["Collapsible", "CollapsibleTitle"]


class CollapsibleTitle(Widget, can_focus=True):
class CollapsibleTitle(Static, can_focus=True):
"""Title and symbol for the Collapsible."""

DEFAULT_CSS = """
Expand Down Expand Up @@ -44,6 +42,7 @@ class CollapsibleTitle(Widget, can_focus=True):
"""

collapsed = reactive(True)
label = reactive("Toggle")

def __init__(
self,
Expand All @@ -57,7 +56,9 @@ def __init__(
self.collapsed_symbol = collapsed_symbol
self.expanded_symbol = expanded_symbol
self.label = label
self.collapse = collapsed
self.collapsed = collapsed
self._collapsed_label = f"{collapsed_symbol} {label}"
self._expanded_label = f"{expanded_symbol} {label}"

class Toggle(Message):
"""Request toggle."""
Expand All @@ -71,18 +72,26 @@ def action_toggle(self) -> None:
"""Toggle the state of the parent collapsible."""
self.post_message(self.Toggle())

def render(self) -> RenderableType:
"""Compose right/down arrow and label."""
def _watch_label(self, label: str) -> None:
self._collapsed_label = f"{self.collapsed_symbol} {label}"
self._expanded_label = f"{self.expanded_symbol} {label}"
if self.collapsed:
return Text(f"{self.collapsed_symbol} {self.label}")
self.update(self._collapsed_label)
else:
self.update(self._expanded_label)

def _watch_collapsed(self, collapsed: bool) -> None:
if collapsed:
self.update(self._collapsed_label)
else:
return Text(f"{self.expanded_symbol} {self.label}")
self.update(self._expanded_label)


class Collapsible(Widget):
"""A collapsible container."""

collapsed = reactive(True)
title = reactive("Toggle")

DEFAULT_CSS = """
Collapsible {
Expand Down Expand Up @@ -169,14 +178,15 @@ def __init__(
classes: The CSS classes of the collapsible.
disabled: Whether the collapsible is disabled or not.
"""
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
self._title = CollapsibleTitle(
label=title,
collapsed_symbol=collapsed_symbol,
expanded_symbol=expanded_symbol,
collapsed=collapsed,
)
self.title = title
self._contents_list: list[Widget] = list(children)
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
self.collapsed = collapsed

def _on_collapsible_title_toggle(self, event: CollapsibleTitle.Toggle) -> None:
Expand Down Expand Up @@ -214,3 +224,6 @@ def compose_add_child(self, widget: Widget) -> None:
widget: A Widget to add.
"""
self._contents_list.append(widget)

def _watch_title(self, title: str) -> None:
self._title.label = title
12 changes: 12 additions & 0 deletions tests/test_collapsible.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,15 @@ def on_collapsible_collapsed(self) -> None:

assert pilot.app.query_one(Collapsible).collapsed
assert len(hits) == 1


async def test_collapsible_title_reactive_change():
class CollapsibleApp(App[None]):
def compose(self) -> ComposeResult:
yield Collapsible(title="Old title")

async with CollapsibleApp().run_test() as pilot:
collapsible = pilot.app.query_one(Collapsible)
assert get_title(collapsible).label == "Old title"
collapsible.title = "New title"
assert get_title(collapsible).label == "New title"

0 comments on commit e72bab3

Please sign in to comment.