mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Update Collapsible (#3305)
* Update Collapsible * snapshot tests * word * Update docs/widgets/collapsible.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * Update docs/widgets/collapsible.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * simplify render --------- Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
This commit is contained in:
@@ -21,7 +21,7 @@ Son of Leto and Jessica.
|
||||
|
||||
|
||||
class CollapsibleApp(App[None]):
|
||||
"""An example of colllapsible container."""
|
||||
"""An example of collapsible container."""
|
||||
|
||||
BINDINGS = [
|
||||
("c", "collapse_or_expand(True)", "Collapse All"),
|
||||
|
||||
@@ -34,6 +34,16 @@ A classic checkbox control.
|
||||
```{.textual path="docs/examples/widgets/checkbox.py"}
|
||||
```
|
||||
|
||||
## Collapsible
|
||||
|
||||
Content that may be toggled on and off by clicking a title.
|
||||
|
||||
[Collapsible reference](./widgets/collapsible.md){ .md-button .md-button--primary }
|
||||
|
||||
|
||||
```{.textual path="docs/examples/widgets/collapsible.py"}
|
||||
```
|
||||
|
||||
|
||||
## ContentSwitcher
|
||||
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
# Collapsible
|
||||
|
||||
!!! tip "Added in version 0.36"
|
||||
!!! tip "Added in version 0.37"
|
||||
|
||||
Widget that wraps its contents in a collapsible container.
|
||||
A container with a title that can be used to show (expand) or hide (collapse) content, either by clicking or focusing and pressing ++enter++.
|
||||
|
||||
- [ ] Focusable
|
||||
- [x] Focusable
|
||||
- [x] Container
|
||||
|
||||
|
||||
## Composing
|
||||
|
||||
There are two ways to wrap other widgets.
|
||||
You can pass them as positional arguments to the [Collapsible][textual.widgets.Collapsible] constructor:
|
||||
You can add content to a Collapsible widget either by passing in children to the constructor, or with a context manager (`with` statement).
|
||||
|
||||
Here is an example of using the constructor to add content:
|
||||
|
||||
```python
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Collapsible(Label("Hello, world."))
|
||||
```
|
||||
|
||||
Alternatively, you can compose other widgets under the context manager:
|
||||
Here's how the to use it with the context manager:
|
||||
|
||||
```python
|
||||
def compose(self) -> ComposeResult:
|
||||
@@ -26,9 +27,11 @@ def compose(self) -> ComposeResult:
|
||||
yield Label("Hello, world.")
|
||||
```
|
||||
|
||||
The second form is generally preferred, but the end result is the same.
|
||||
|
||||
## Title
|
||||
|
||||
The default title "Toggle" of the `Collapsible` widget can be customized by specifying the parameter `title` of the constructor:
|
||||
The default title "Toggle" can be customized by setting the `title` parameter of the constructor:
|
||||
|
||||
```python
|
||||
def compose(self) -> ComposeResult:
|
||||
@@ -38,7 +41,7 @@ def compose(self) -> ComposeResult:
|
||||
|
||||
## Initial State
|
||||
|
||||
The initial state of the `Collapsible` widget can be customized via the parameter `collapsed` of the constructor:
|
||||
The initial state of the `Collapsible` widget can be customized via the `collapsed` parameter of the constructor:
|
||||
|
||||
```python
|
||||
def compose(self) -> ComposeResult:
|
||||
@@ -51,7 +54,7 @@ def compose(self) -> ComposeResult:
|
||||
|
||||
## Collapse/Expand Symbols
|
||||
|
||||
The symbols `►` and `▼` of the `Collapsible` widget can be customized by specifying the parameters `collapsed_symbol` and `expanded_symbol`, respectively, of the `Collapsible` constructor:
|
||||
The symbols used to show the collapsed / expanded state can be customized by setting the parameters `collapsed_symbol` and `expanded_symbol`:
|
||||
|
||||
```python
|
||||
def compose(self) -> ComposeResult:
|
||||
@@ -59,31 +62,19 @@ def compose(self) -> ComposeResult:
|
||||
yield Label("Hello, world.")
|
||||
```
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="tests/snapshot_tests/snapshot_apps/collapsible_custom_symbol.py"}
|
||||
```
|
||||
|
||||
=== "collapsible_custom_symbol.py"
|
||||
|
||||
```python
|
||||
--8<-- "tests/snapshot_tests/snapshot_apps/collapsible_custom_symbol.py"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic example
|
||||
|
||||
The following example contains three `Collapsible`s in different states.
|
||||
|
||||
=== "All expanded"
|
||||
|
||||
```{.textual path="docs/examples/widgets/collapsible.py press="e"}
|
||||
```{.textual path="docs/examples/widgets/collapsible.py" press="e"}
|
||||
```
|
||||
|
||||
=== "All collapsed"
|
||||
|
||||
```{.textual path="docs/examples/widgets/collapsible.py press="c"}
|
||||
```{.textual path="docs/examples/widgets/collapsible.py" press="c"}
|
||||
```
|
||||
|
||||
=== "Mixed"
|
||||
@@ -104,49 +95,37 @@ The example below shows nested `Collapsible` widgets and how to set their initia
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="tests/snapshot_tests/snapshot_apps/collapsible_nested.py"}
|
||||
```{.textual path="docs/examples/widgets/collapsible_nested.py"}
|
||||
```
|
||||
|
||||
=== "collapsible_nested.py"
|
||||
|
||||
```python hl_lines="7"
|
||||
--8<-- "tests/snapshot_tests/snapshot_apps/collapsible_nested.py"
|
||||
--8<-- "docs/examples/widgets/collapsible_nested.py"
|
||||
```
|
||||
|
||||
### Custom Symbols
|
||||
|
||||
The app below shows `Collapsible` widgets with custom expand/collapse symbols.
|
||||
The following example shows `Collapsible` widgets with custom expand/collapse symbols.
|
||||
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="tests/snapshot_tests/snapshot_apps/collapsible_custom_symbol.py"}
|
||||
```{.textual path="docs/examples/widgets/collapsible_custom_symbol.py"}
|
||||
```
|
||||
|
||||
=== "collapsible_custom_symbol.py"
|
||||
|
||||
```python
|
||||
--8<-- "tests/snapshot_tests/snapshot_apps/collapsible_custom_symbol.py"
|
||||
--8<-- "docs/examples/widgets/collapsible_custom_symbol.py"
|
||||
```
|
||||
|
||||
## Reactive attributes
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | -------------------------------------------------------------- |
|
||||
| Name | Type | Default | Description |
|
||||
| ----------- | ------ | ------- | ---------------------------------------------------- |
|
||||
| `collapsed` | `bool` | `True` | Controls the collapsed/expanded state of the widget. |
|
||||
|
||||
## Messages
|
||||
|
||||
- [Collapsible.Title.Toggle][textual.widgets.Collapsible.Title.Toggle]
|
||||
|
||||
<!--
|
||||
## See also
|
||||
|
||||
TODO: Add Accordion widgets later
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
|
||||
::: textual.widgets.Collapsible
|
||||
options:
|
||||
|
||||
@@ -46,18 +46,18 @@ theme:
|
||||
- content.code.annotate
|
||||
- content.code.copy
|
||||
palette:
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
accent: purple
|
||||
toggle:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: black
|
||||
toggle:
|
||||
icon: material/weather-night
|
||||
name: Switch to light mode
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
accent: purple
|
||||
toggle:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: black
|
||||
toggle:
|
||||
icon: material/weather-night
|
||||
name: Switch to light mode
|
||||
|
||||
plugins:
|
||||
search:
|
||||
@@ -87,6 +87,7 @@ plugins:
|
||||
- "!^render_lines$"
|
||||
- "!^get_content_width$"
|
||||
- "!^get_content_height$"
|
||||
- "!^compose_add_child$"
|
||||
watch:
|
||||
- mkdocs-common.yml
|
||||
- mkdocs-nav.yml
|
||||
@@ -98,11 +99,9 @@ plugins:
|
||||
- "**/_template.md"
|
||||
- "snippets/*"
|
||||
|
||||
|
||||
extra_css:
|
||||
- stylesheets/custom.css
|
||||
|
||||
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/twitter
|
||||
|
||||
421
mkdocs-nav.yml
421
mkdocs-nav.yml
@@ -1,211 +1,212 @@
|
||||
nav:
|
||||
- Introduction:
|
||||
- "index.md"
|
||||
- "getting_started.md"
|
||||
- "help.md"
|
||||
- "tutorial.md"
|
||||
- Guide:
|
||||
- "guide/index.md"
|
||||
- "guide/devtools.md"
|
||||
- "guide/app.md"
|
||||
- "guide/styles.md"
|
||||
- "guide/CSS.md"
|
||||
- "guide/design.md"
|
||||
- "guide/queries.md"
|
||||
- "guide/layout.md"
|
||||
- "guide/events.md"
|
||||
- "guide/input.md"
|
||||
- "guide/actions.md"
|
||||
- "guide/reactivity.md"
|
||||
- "guide/widgets.md"
|
||||
- "guide/animation.md"
|
||||
- "guide/screens.md"
|
||||
- "guide/workers.md"
|
||||
- "guide/command_palette.md"
|
||||
- "widget_gallery.md"
|
||||
- Reference:
|
||||
- "reference/index.md"
|
||||
- CSS Types:
|
||||
- "css_types/index.md"
|
||||
- "css_types/border.md"
|
||||
- "css_types/color.md"
|
||||
- "css_types/horizontal.md"
|
||||
- "css_types/integer.md"
|
||||
- "css_types/name.md"
|
||||
- "css_types/number.md"
|
||||
- "css_types/overflow.md"
|
||||
- "css_types/percentage.md"
|
||||
- "css_types/scalar.md"
|
||||
- "css_types/text_align.md"
|
||||
- "css_types/text_style.md"
|
||||
- "css_types/vertical.md"
|
||||
- Events:
|
||||
- "events/index.md"
|
||||
- "events/blur.md"
|
||||
- "events/descendant_blur.md"
|
||||
- "events/descendant_focus.md"
|
||||
- "events/enter.md"
|
||||
- "events/focus.md"
|
||||
- "events/hide.md"
|
||||
- "events/key.md"
|
||||
- "events/leave.md"
|
||||
- "events/load.md"
|
||||
- "events/mount.md"
|
||||
- "events/mouse_capture.md"
|
||||
- "events/click.md"
|
||||
- "events/mouse_down.md"
|
||||
- "events/mouse_move.md"
|
||||
- "events/mouse_release.md"
|
||||
- "events/mouse_scroll_down.md"
|
||||
- "events/mouse_scroll_up.md"
|
||||
- "events/mouse_up.md"
|
||||
- "events/paste.md"
|
||||
- "events/resize.md"
|
||||
- "events/screen_resume.md"
|
||||
- "events/screen_suspend.md"
|
||||
- "events/show.md"
|
||||
- Styles:
|
||||
- "styles/align.md"
|
||||
- "styles/background.md"
|
||||
- "styles/border.md"
|
||||
- "styles/border_subtitle_align.md"
|
||||
- "styles/border_subtitle_background.md"
|
||||
- "styles/border_subtitle_color.md"
|
||||
- "styles/border_subtitle_style.md"
|
||||
- "styles/border_title_align.md"
|
||||
- "styles/border_title_background.md"
|
||||
- "styles/border_title_color.md"
|
||||
- "styles/border_title_style.md"
|
||||
- "styles/box_sizing.md"
|
||||
- "styles/color.md"
|
||||
- "styles/content_align.md"
|
||||
- "styles/display.md"
|
||||
- "styles/dock.md"
|
||||
- "styles/index.md"
|
||||
- Grid:
|
||||
- "styles/grid/index.md"
|
||||
- "styles/grid/column_span.md"
|
||||
- "styles/grid/grid_columns.md"
|
||||
- "styles/grid/grid_gutter.md"
|
||||
- "styles/grid/grid_rows.md"
|
||||
- "styles/grid/grid_size.md"
|
||||
- "styles/grid/row_span.md"
|
||||
- "styles/height.md"
|
||||
- "styles/layer.md"
|
||||
- "styles/layers.md"
|
||||
- "styles/layout.md"
|
||||
- Links:
|
||||
- "styles/links/index.md"
|
||||
- "styles/links/link_background.md"
|
||||
- "styles/links/link_color.md"
|
||||
- "styles/links/link_hover_background.md"
|
||||
- "styles/links/link_hover_color.md"
|
||||
- "styles/links/link_hover_style.md"
|
||||
- "styles/links/link_style.md"
|
||||
- "styles/margin.md"
|
||||
- "styles/max_height.md"
|
||||
- "styles/max_width.md"
|
||||
- "styles/min_height.md"
|
||||
- "styles/min_width.md"
|
||||
- "styles/offset.md"
|
||||
- "styles/opacity.md"
|
||||
- "styles/outline.md"
|
||||
- "styles/overflow.md"
|
||||
- "styles/padding.md"
|
||||
- Scrollbar colors:
|
||||
- "styles/scrollbar_colors/index.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background_active.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background_hover.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color_active.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color_hover.md"
|
||||
- "styles/scrollbar_colors/scrollbar_corner_color.md"
|
||||
- "styles/scrollbar_gutter.md"
|
||||
- "styles/scrollbar_size.md"
|
||||
- "styles/text_align.md"
|
||||
- "styles/text_opacity.md"
|
||||
- "styles/text_style.md"
|
||||
- "styles/tint.md"
|
||||
- "styles/visibility.md"
|
||||
- "styles/width.md"
|
||||
- Widgets:
|
||||
- "widgets/button.md"
|
||||
- "widgets/checkbox.md"
|
||||
- "widgets/content_switcher.md"
|
||||
- "widgets/data_table.md"
|
||||
- "widgets/digits.md"
|
||||
- "widgets/directory_tree.md"
|
||||
- "widgets/footer.md"
|
||||
- "widgets/header.md"
|
||||
- "widgets/index.md"
|
||||
- "widgets/input.md"
|
||||
- "widgets/label.md"
|
||||
- "widgets/list_item.md"
|
||||
- "widgets/list_view.md"
|
||||
- "widgets/loading_indicator.md"
|
||||
- "widgets/log.md"
|
||||
- "widgets/markdown_viewer.md"
|
||||
- "widgets/markdown.md"
|
||||
- "widgets/option_list.md"
|
||||
- "widgets/placeholder.md"
|
||||
- "widgets/pretty.md"
|
||||
- "widgets/progress_bar.md"
|
||||
- "widgets/radiobutton.md"
|
||||
- "widgets/radioset.md"
|
||||
- "widgets/rich_log.md"
|
||||
- "widgets/rule.md"
|
||||
- "widgets/select.md"
|
||||
- "widgets/selection_list.md"
|
||||
- "widgets/sparkline.md"
|
||||
- "widgets/static.md"
|
||||
- "widgets/switch.md"
|
||||
- "widgets/tabbed_content.md"
|
||||
- "widgets/tabs.md"
|
||||
- "widgets/tree.md"
|
||||
- API:
|
||||
- "api/index.md"
|
||||
- "api/app.md"
|
||||
- "api/await_remove.md"
|
||||
- "api/binding.md"
|
||||
- "api/color.md"
|
||||
- "api/command.md"
|
||||
- "api/containers.md"
|
||||
- "api/coordinate.md"
|
||||
- "api/dom_node.md"
|
||||
- "api/events.md"
|
||||
- "api/errors.md"
|
||||
- "api/filter.md"
|
||||
- "api/fuzzy_matcher.md"
|
||||
- "api/geometry.md"
|
||||
- "api/logger.md"
|
||||
- "api/logging.md"
|
||||
- "api/map_geometry.md"
|
||||
- "api/message_pump.md"
|
||||
- "api/message.md"
|
||||
- "api/on.md"
|
||||
- "api/pilot.md"
|
||||
- "api/query.md"
|
||||
- "api/reactive.md"
|
||||
- "api/screen.md"
|
||||
- "api/scrollbar.md"
|
||||
- "api/scroll_view.md"
|
||||
- "api/strip.md"
|
||||
- "api/suggester.md"
|
||||
- "api/system_commands_source.md"
|
||||
- "api/timer.md"
|
||||
- "api/types.md"
|
||||
- "api/validation.md"
|
||||
- "api/walk.md"
|
||||
- "api/widget.md"
|
||||
- "api/work.md"
|
||||
- "api/worker.md"
|
||||
- "api/worker_manager.md"
|
||||
- "How To":
|
||||
- "how-to/index.md"
|
||||
- "how-to/center-things.md"
|
||||
- "how-to/design-a-layout.md"
|
||||
- "FAQ.md"
|
||||
- "roadmap.md"
|
||||
- "Blog":
|
||||
- blog/index.md
|
||||
- Introduction:
|
||||
- "index.md"
|
||||
- "getting_started.md"
|
||||
- "help.md"
|
||||
- "tutorial.md"
|
||||
- Guide:
|
||||
- "guide/index.md"
|
||||
- "guide/devtools.md"
|
||||
- "guide/app.md"
|
||||
- "guide/styles.md"
|
||||
- "guide/CSS.md"
|
||||
- "guide/design.md"
|
||||
- "guide/queries.md"
|
||||
- "guide/layout.md"
|
||||
- "guide/events.md"
|
||||
- "guide/input.md"
|
||||
- "guide/actions.md"
|
||||
- "guide/reactivity.md"
|
||||
- "guide/widgets.md"
|
||||
- "guide/animation.md"
|
||||
- "guide/screens.md"
|
||||
- "guide/workers.md"
|
||||
- "guide/command_palette.md"
|
||||
- "widget_gallery.md"
|
||||
- Reference:
|
||||
- "reference/index.md"
|
||||
- CSS Types:
|
||||
- "css_types/index.md"
|
||||
- "css_types/border.md"
|
||||
- "css_types/color.md"
|
||||
- "css_types/horizontal.md"
|
||||
- "css_types/integer.md"
|
||||
- "css_types/name.md"
|
||||
- "css_types/number.md"
|
||||
- "css_types/overflow.md"
|
||||
- "css_types/percentage.md"
|
||||
- "css_types/scalar.md"
|
||||
- "css_types/text_align.md"
|
||||
- "css_types/text_style.md"
|
||||
- "css_types/vertical.md"
|
||||
- Events:
|
||||
- "events/index.md"
|
||||
- "events/blur.md"
|
||||
- "events/descendant_blur.md"
|
||||
- "events/descendant_focus.md"
|
||||
- "events/enter.md"
|
||||
- "events/focus.md"
|
||||
- "events/hide.md"
|
||||
- "events/key.md"
|
||||
- "events/leave.md"
|
||||
- "events/load.md"
|
||||
- "events/mount.md"
|
||||
- "events/mouse_capture.md"
|
||||
- "events/click.md"
|
||||
- "events/mouse_down.md"
|
||||
- "events/mouse_move.md"
|
||||
- "events/mouse_release.md"
|
||||
- "events/mouse_scroll_down.md"
|
||||
- "events/mouse_scroll_up.md"
|
||||
- "events/mouse_up.md"
|
||||
- "events/paste.md"
|
||||
- "events/resize.md"
|
||||
- "events/screen_resume.md"
|
||||
- "events/screen_suspend.md"
|
||||
- "events/show.md"
|
||||
- Styles:
|
||||
- "styles/align.md"
|
||||
- "styles/background.md"
|
||||
- "styles/border.md"
|
||||
- "styles/border_subtitle_align.md"
|
||||
- "styles/border_subtitle_background.md"
|
||||
- "styles/border_subtitle_color.md"
|
||||
- "styles/border_subtitle_style.md"
|
||||
- "styles/border_title_align.md"
|
||||
- "styles/border_title_background.md"
|
||||
- "styles/border_title_color.md"
|
||||
- "styles/border_title_style.md"
|
||||
- "styles/box_sizing.md"
|
||||
- "styles/color.md"
|
||||
- "styles/content_align.md"
|
||||
- "styles/display.md"
|
||||
- "styles/dock.md"
|
||||
- "styles/index.md"
|
||||
- Grid:
|
||||
- "styles/grid/index.md"
|
||||
- "styles/grid/column_span.md"
|
||||
- "styles/grid/grid_columns.md"
|
||||
- "styles/grid/grid_gutter.md"
|
||||
- "styles/grid/grid_rows.md"
|
||||
- "styles/grid/grid_size.md"
|
||||
- "styles/grid/row_span.md"
|
||||
- "styles/height.md"
|
||||
- "styles/layer.md"
|
||||
- "styles/layers.md"
|
||||
- "styles/layout.md"
|
||||
- Links:
|
||||
- "styles/links/index.md"
|
||||
- "styles/links/link_background.md"
|
||||
- "styles/links/link_color.md"
|
||||
- "styles/links/link_hover_background.md"
|
||||
- "styles/links/link_hover_color.md"
|
||||
- "styles/links/link_hover_style.md"
|
||||
- "styles/links/link_style.md"
|
||||
- "styles/margin.md"
|
||||
- "styles/max_height.md"
|
||||
- "styles/max_width.md"
|
||||
- "styles/min_height.md"
|
||||
- "styles/min_width.md"
|
||||
- "styles/offset.md"
|
||||
- "styles/opacity.md"
|
||||
- "styles/outline.md"
|
||||
- "styles/overflow.md"
|
||||
- "styles/padding.md"
|
||||
- Scrollbar colors:
|
||||
- "styles/scrollbar_colors/index.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background_active.md"
|
||||
- "styles/scrollbar_colors/scrollbar_background_hover.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color_active.md"
|
||||
- "styles/scrollbar_colors/scrollbar_color_hover.md"
|
||||
- "styles/scrollbar_colors/scrollbar_corner_color.md"
|
||||
- "styles/scrollbar_gutter.md"
|
||||
- "styles/scrollbar_size.md"
|
||||
- "styles/text_align.md"
|
||||
- "styles/text_opacity.md"
|
||||
- "styles/text_style.md"
|
||||
- "styles/tint.md"
|
||||
- "styles/visibility.md"
|
||||
- "styles/width.md"
|
||||
- Widgets:
|
||||
- "widgets/button.md"
|
||||
- "widgets/checkbox.md"
|
||||
- "widgets/collapsible.md"
|
||||
- "widgets/content_switcher.md"
|
||||
- "widgets/data_table.md"
|
||||
- "widgets/digits.md"
|
||||
- "widgets/directory_tree.md"
|
||||
- "widgets/footer.md"
|
||||
- "widgets/header.md"
|
||||
- "widgets/index.md"
|
||||
- "widgets/input.md"
|
||||
- "widgets/label.md"
|
||||
- "widgets/list_item.md"
|
||||
- "widgets/list_view.md"
|
||||
- "widgets/loading_indicator.md"
|
||||
- "widgets/log.md"
|
||||
- "widgets/markdown_viewer.md"
|
||||
- "widgets/markdown.md"
|
||||
- "widgets/option_list.md"
|
||||
- "widgets/placeholder.md"
|
||||
- "widgets/pretty.md"
|
||||
- "widgets/progress_bar.md"
|
||||
- "widgets/radiobutton.md"
|
||||
- "widgets/radioset.md"
|
||||
- "widgets/rich_log.md"
|
||||
- "widgets/rule.md"
|
||||
- "widgets/select.md"
|
||||
- "widgets/selection_list.md"
|
||||
- "widgets/sparkline.md"
|
||||
- "widgets/static.md"
|
||||
- "widgets/switch.md"
|
||||
- "widgets/tabbed_content.md"
|
||||
- "widgets/tabs.md"
|
||||
- "widgets/tree.md"
|
||||
- API:
|
||||
- "api/index.md"
|
||||
- "api/app.md"
|
||||
- "api/await_remove.md"
|
||||
- "api/binding.md"
|
||||
- "api/color.md"
|
||||
- "api/command.md"
|
||||
- "api/containers.md"
|
||||
- "api/coordinate.md"
|
||||
- "api/dom_node.md"
|
||||
- "api/events.md"
|
||||
- "api/errors.md"
|
||||
- "api/filter.md"
|
||||
- "api/fuzzy_matcher.md"
|
||||
- "api/geometry.md"
|
||||
- "api/logger.md"
|
||||
- "api/logging.md"
|
||||
- "api/map_geometry.md"
|
||||
- "api/message_pump.md"
|
||||
- "api/message.md"
|
||||
- "api/on.md"
|
||||
- "api/pilot.md"
|
||||
- "api/query.md"
|
||||
- "api/reactive.md"
|
||||
- "api/screen.md"
|
||||
- "api/scrollbar.md"
|
||||
- "api/scroll_view.md"
|
||||
- "api/strip.md"
|
||||
- "api/suggester.md"
|
||||
- "api/system_commands_source.md"
|
||||
- "api/timer.md"
|
||||
- "api/types.md"
|
||||
- "api/validation.md"
|
||||
- "api/walk.md"
|
||||
- "api/widget.md"
|
||||
- "api/work.md"
|
||||
- "api/worker.md"
|
||||
- "api/worker_manager.md"
|
||||
- "How To":
|
||||
- "how-to/index.md"
|
||||
- "how-to/center-things.md"
|
||||
- "how-to/design-a-layout.md"
|
||||
- "FAQ.md"
|
||||
- "roadmap.md"
|
||||
- "Blog":
|
||||
- blog/index.md
|
||||
|
||||
@@ -1,16 +1,76 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from textual.widget import Widget
|
||||
from rich.console import RenderableType
|
||||
from rich.text import Text
|
||||
|
||||
from .. import events
|
||||
from ..app import ComposeResult
|
||||
from ..containers import Container, Horizontal
|
||||
from ..binding import Binding
|
||||
from ..containers import Container
|
||||
from ..css.query import NoMatches
|
||||
from ..message import Message
|
||||
from ..reactive import reactive
|
||||
from ..widget import Widget
|
||||
from ..widgets import Label
|
||||
|
||||
__all__ = ["Collapsible"]
|
||||
__all__ = ["Collapsible", "CollapsibleTitle"]
|
||||
|
||||
|
||||
class CollapsibleTitle(Widget, can_focus=True):
|
||||
"""Title and symbol for the Collapsible."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
CollapsibleTitle {
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 0 1 0 1;
|
||||
}
|
||||
|
||||
CollapsibleTitle:hover {
|
||||
background: $foreground 10%;
|
||||
color: $text;
|
||||
}
|
||||
|
||||
CollapsibleTitle:focus {
|
||||
background: $accent;
|
||||
}
|
||||
"""
|
||||
|
||||
BINDINGS = [Binding("enter", "toggle", "Toggle collapsible", show=False)]
|
||||
|
||||
collapsed = reactive(True)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
label: str,
|
||||
collapsed_symbol: str,
|
||||
expanded_symbol: str,
|
||||
collapsed: bool,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.collapsed_symbol = collapsed_symbol
|
||||
self.expanded_symbol = expanded_symbol
|
||||
self.label = label
|
||||
self.collapse = collapsed
|
||||
|
||||
class Toggle(Message):
|
||||
"""Request toggle."""
|
||||
|
||||
async def _on_click(self, event: events.Click) -> None:
|
||||
"""Inform ancestor we want to toggle."""
|
||||
event.stop()
|
||||
self.post_message(self.Toggle())
|
||||
|
||||
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."""
|
||||
if self.collapsed:
|
||||
return Text(f"{self.collapsed_symbol} {self.label}")
|
||||
else:
|
||||
return Text(f"{self.expanded_symbol} {self.label}")
|
||||
|
||||
|
||||
class Collapsible(Widget):
|
||||
@@ -23,66 +83,12 @@ class Collapsible(Widget):
|
||||
width: 1fr;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
Collapsible.-collapsed > Contents {
|
||||
display: none;
|
||||
}
|
||||
"""
|
||||
|
||||
class Title(Horizontal):
|
||||
DEFAULT_CSS = """
|
||||
Title {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
Title:hover {
|
||||
background: grey;
|
||||
}
|
||||
|
||||
Title .label {
|
||||
padding: 0 0 0 1;
|
||||
}
|
||||
|
||||
Title #collapsed-symbol {
|
||||
display:none;
|
||||
}
|
||||
|
||||
Title.-collapsed #expanded-symbol {
|
||||
display:none;
|
||||
}
|
||||
|
||||
Title.-collapsed #collapsed-symbol {
|
||||
display:block;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
label: str,
|
||||
collapsed_symbol: str,
|
||||
expanded_symbol: str,
|
||||
name: str | None = None,
|
||||
id: str | None = None,
|
||||
classes: str | None = None,
|
||||
disabled: bool = False,
|
||||
) -> None:
|
||||
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
|
||||
self.collapsed_symbol = collapsed_symbol
|
||||
self.expanded_symbol = expanded_symbol
|
||||
self.label = label
|
||||
|
||||
class Toggle(Message):
|
||||
"""Request toggle."""
|
||||
|
||||
async def _on_click(self, event: events.Click) -> None:
|
||||
"""Inform ancestor we want to toggle."""
|
||||
event.stop()
|
||||
self.post_message(self.Toggle())
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""Compose right/down arrow and label."""
|
||||
yield Label(self.expanded_symbol, classes="label", id="expanded-symbol")
|
||||
yield Label(self.collapsed_symbol, classes="label", id="collapsed-symbol")
|
||||
yield Label(self.label, classes="label")
|
||||
|
||||
class Contents(Container):
|
||||
DEFAULT_CSS = """
|
||||
Contents {
|
||||
@@ -91,9 +97,6 @@ class Collapsible(Widget):
|
||||
padding: 0 0 0 3;
|
||||
}
|
||||
|
||||
Contents.-collapsed {
|
||||
display: none;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -101,7 +104,7 @@ class Collapsible(Widget):
|
||||
*children: Widget,
|
||||
title: str = "Toggle",
|
||||
collapsed: bool = True,
|
||||
collapsed_symbol: str = "►",
|
||||
collapsed_symbol: str = "▶",
|
||||
expanded_symbol: str = "▼",
|
||||
name: str | None = None,
|
||||
id: str | None = None,
|
||||
@@ -121,31 +124,39 @@ class Collapsible(Widget):
|
||||
classes: The CSS classes of the collapsible.
|
||||
disabled: Whether the collapsible is disabled or not.
|
||||
"""
|
||||
self._title = self.Title(
|
||||
self._title = CollapsibleTitle(
|
||||
label=title,
|
||||
collapsed_symbol=collapsed_symbol,
|
||||
expanded_symbol=expanded_symbol,
|
||||
collapsed=collapsed,
|
||||
)
|
||||
self._contents_list: list[Widget] = list(children)
|
||||
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
|
||||
self.collapsed = collapsed
|
||||
|
||||
def _on_title_toggle(self, event: Title.Toggle) -> None:
|
||||
def on_collapsible_title_toggle(self, event: CollapsibleTitle.Toggle) -> None:
|
||||
event.stop()
|
||||
self.collapsed = not self.collapsed
|
||||
|
||||
def watch_collapsed(self) -> None:
|
||||
for child in self._nodes:
|
||||
child.set_class(self.collapsed, "-collapsed")
|
||||
def _watch_collapsed(self, collapsed: bool) -> None:
|
||||
"""Update collapsed state when reactive is changed."""
|
||||
self._update_collapsed(collapsed)
|
||||
|
||||
def _update_collapsed(self, collapsed: bool) -> None:
|
||||
"""Update children to match collapsed state."""
|
||||
try:
|
||||
self._title.collapsed = collapsed
|
||||
self.set_class(collapsed, "-collapsed")
|
||||
except NoMatches:
|
||||
pass
|
||||
|
||||
def _on_mount(self) -> None:
|
||||
"""Initialise collapsed state."""
|
||||
self._update_collapsed(self.collapsed)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield from (
|
||||
child.set_class(self.collapsed, "-collapsed")
|
||||
for child in (
|
||||
self._title,
|
||||
self.Contents(*self._contents_list),
|
||||
)
|
||||
)
|
||||
yield self._title
|
||||
yield self.Contents(*self._contents_list)
|
||||
|
||||
def compose_add_child(self, widget: Widget) -> None:
|
||||
"""When using the context manager compose syntax, we want to attach nodes to the contents.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,12 +2,13 @@ from __future__ import annotations
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Collapsible, Label
|
||||
from textual.widgets._collapsible import CollapsibleTitle
|
||||
|
||||
COLLAPSED_CLASS = "-collapsed"
|
||||
|
||||
|
||||
def get_title(collapsible: Collapsible) -> Collapsible.Title:
|
||||
return collapsible.get_child_by_type(Collapsible.Title)
|
||||
def get_title(collapsible: Collapsible) -> CollapsibleTitle:
|
||||
return collapsible.get_child_by_type(CollapsibleTitle)
|
||||
|
||||
|
||||
def get_contents(collapsible: Collapsible) -> Collapsible.Contents:
|
||||
@@ -31,9 +32,7 @@ async def test_compose_default_collapsible():
|
||||
async with CollapsibleApp().run_test() as pilot:
|
||||
collapsible = pilot.app.query_one(Collapsible)
|
||||
assert get_title(collapsible).label == "Toggle"
|
||||
assert get_title(collapsible).has_class(COLLAPSED_CLASS)
|
||||
assert len(get_contents(collapsible).children) == 1
|
||||
assert get_contents(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
|
||||
async def test_compose_empty_collapsible():
|
||||
@@ -76,32 +75,6 @@ async def test_compose_expanded_collapsible():
|
||||
assert not get_contents(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
|
||||
async def test_collapsible_collapsed_title_label():
|
||||
"""Collapsed title label should be displayed."""
|
||||
|
||||
class CollapsibleApp(App[None]):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Collapsible(Label("Some Contents"), collapsed=True)
|
||||
|
||||
async with CollapsibleApp().run_test() as pilot:
|
||||
title = get_title(pilot.app.query_one(Collapsible))
|
||||
assert not title.get_child_by_id("expanded-symbol").display
|
||||
assert title.get_child_by_id("collapsed-symbol").display
|
||||
|
||||
|
||||
async def test_collapsible_expanded_title_label():
|
||||
"""Expanded title label should be displayed."""
|
||||
|
||||
class CollapsibleApp(App[None]):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Collapsible(Label("Some Contents"), collapsed=False)
|
||||
|
||||
async with CollapsibleApp().run_test() as pilot:
|
||||
title = get_title(pilot.app.query_one(Collapsible))
|
||||
assert title.get_child_by_id("expanded-symbol").display
|
||||
assert not title.get_child_by_id("collapsed-symbol").display
|
||||
|
||||
|
||||
async def test_collapsible_collapsed_contents_display_false():
|
||||
"""Test default settings of Collapsible with 1 widget in contents."""
|
||||
|
||||
@@ -126,22 +99,6 @@ async def test_collapsible_expanded_contents_display_true():
|
||||
assert get_contents(collapsible).display
|
||||
|
||||
|
||||
async def test_reactive_collapsed():
|
||||
"""Updating ``collapsed`` should change classes of children."""
|
||||
|
||||
class CollapsibleApp(App[None]):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Collapsible(collapsed=False)
|
||||
|
||||
async with CollapsibleApp().run_test() as pilot:
|
||||
collapsible = pilot.app.query_one(Collapsible)
|
||||
assert not get_title(collapsible).has_class(COLLAPSED_CLASS)
|
||||
collapsible.collapsed = True
|
||||
assert get_contents(collapsible).has_class(COLLAPSED_CLASS)
|
||||
collapsible.collapsed = False
|
||||
assert not get_title(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
|
||||
async def test_toggle_title():
|
||||
"""Clicking title should update ``collapsed``."""
|
||||
|
||||
@@ -152,12 +109,9 @@ async def test_toggle_title():
|
||||
async with CollapsibleApp().run_test() as pilot:
|
||||
collapsible = pilot.app.query_one(Collapsible)
|
||||
assert not collapsible.collapsed
|
||||
assert not get_title(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
await pilot.click(Collapsible.Title)
|
||||
await pilot.click(CollapsibleTitle)
|
||||
assert collapsible.collapsed
|
||||
assert get_contents(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
await pilot.click(Collapsible.Title)
|
||||
await pilot.click(CollapsibleTitle)
|
||||
assert not collapsible.collapsed
|
||||
assert not get_title(collapsible).has_class(COLLAPSED_CLASS)
|
||||
|
||||
Reference in New Issue
Block a user