mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
new blog post
This commit is contained in:
@@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
## [0.6.0] - Unreleased
|
## [0.6.0] - 2022-12-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|||||||
77
docs/blog/posts/release0-6-0.md
Normal file
77
docs/blog/posts/release0-6-0.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
draft: true
|
||||||
|
date: 2022-12-11
|
||||||
|
categories:
|
||||||
|
- Release
|
||||||
|
title: "version-060"
|
||||||
|
authors:
|
||||||
|
- willmcgugan
|
||||||
|
---
|
||||||
|
|
||||||
|
# Textual 0.6.0 adds a *tree*mendous new widget
|
||||||
|
|
||||||
|
A new release of Textual lands 3 weeks after the previous release -- and it's a big one.
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
|
!!! information
|
||||||
|
|
||||||
|
If you're new here, [Textual](https://github.com/Textualize/textual) is TUI framework for Python.
|
||||||
|
|
||||||
|
## Tree Control
|
||||||
|
|
||||||
|
The headline feature of version 0.6.0 is a new tree control built from the ground-up. The previous Tree control suffered from an overly complex API and wasn't scalable (scrolling slowed down with 1000s of nodes).
|
||||||
|
|
||||||
|
This new version has a simpler API and is highly scalable (no slowdown with larger trees). There are also a number of visual enhancements in this version.
|
||||||
|
|
||||||
|
Here's a very simple example:
|
||||||
|
|
||||||
|
=== "Output"
|
||||||
|
|
||||||
|
```{.textual path="docs/examples/widgets/tree.py"}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "tree.py"
|
||||||
|
|
||||||
|
```python
|
||||||
|
--8<-- "docs/examples/widgets/tree.py"
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's the tree control being used to navigate some JSON ([json_tree.py](https://github.com/Textualize/textual/blob/main/examples/json_tree.py) in the examples directory).
|
||||||
|
|
||||||
|
<div class="video-wrapper">
|
||||||
|
<iframe width="auto" src="https://www.youtube.com/embed/Fy9fPL37P6o" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
I'm biased of course, but I think this terminal based tree control is more usable (and even prettier) than just about anything I've seen on the web or desktop. So much of computing tends to organize itself in to a tree that I think this widget will find a lot of uses.
|
||||||
|
|
||||||
|
The Tree control forms the foundation of the [DirectoryTree](../../widgets/directory_tree.md) widget, which has also been updated. Here it is used in the [code_browser.py](https://github.com/Textualize/textual/blob/main/examples/code_browser.py) example:
|
||||||
|
|
||||||
|
<div class="video-wrapper">
|
||||||
|
<iframe width="auto" src="https://www.youtube.com/embed/ZrYWyZXuYRY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## List View
|
||||||
|
|
||||||
|
We have a new list view control to navigate and select items in a list. Items can be widgets themselves, which makes this a great platform for building more sophisticated controls.
|
||||||
|
|
||||||
|
```{.textual path="docs/examples/widgets/list_view.py"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Placeholder
|
||||||
|
|
||||||
|
The Placeholder widget was broken since the big CSS update. We've brought it back and given it a bit of a polish.
|
||||||
|
|
||||||
|
Use this widget in place of custom widgets you have yet to build when designing your UI.
|
||||||
|
|
||||||
|
```{.textual path="docs/examples/widgets/placeholder.py"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
As always, there are a number of fixes in this release. Mostly related to layout. See [CHANGELOG.md](https://github.com/Textualize/textual/blob/main/CHANGELOG.md) for the details.
|
||||||
|
|
||||||
|
## What's next?
|
||||||
|
|
||||||
|
The next release will focus on *pain points* we discovered while in a dog-fooding phase (see the [DevLog](https://textual.textualize.io/blog/category/devlog/) for details on what Textual devs have been building).
|
||||||
|
|
||||||
@@ -4,12 +4,12 @@ from textual.widgets import Tree
|
|||||||
|
|
||||||
class TreeApp(App):
|
class TreeApp(App):
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
tree: Tree = Tree("Dune")
|
tree: Tree[dict] = Tree("Dune")
|
||||||
tree.root.expand()
|
tree.root.expand()
|
||||||
characters = tree.root.add("Characters", expand=True)
|
characters = tree.root.add("Characters", expand=True)
|
||||||
characters.add_leaf("Paul")
|
characters.add_leaf("Paul")
|
||||||
characters.add_leaf("Jessica")
|
characters.add_leaf("Jessica")
|
||||||
characters.add_leaf("Channi")
|
characters.add_leaf("Chani")
|
||||||
yield tree
|
yield tree
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,5 +39,5 @@ The `DirectoryTree.FileSelected` message is sent when the user selects a file in
|
|||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
* [Tree][textual.widgets.DirectoryTree] code reference
|
* [DirectoryTree][textual.widgets.DirectoryTree] code reference
|
||||||
* [Tree][textual.widgets.Tree] code reference
|
* [Tree][textual.widgets.Tree] code reference
|
||||||
|
|||||||
@@ -33,6 +33,13 @@ class TreeApp(App):
|
|||||||
highlighter = ReprHighlighter()
|
highlighter = ReprHighlighter()
|
||||||
|
|
||||||
def add_node(name: str, node: TreeNode, data: object) -> None:
|
def add_node(name: str, node: TreeNode, data: object) -> None:
|
||||||
|
"""Adds a node to the tree.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): Name of the node.
|
||||||
|
node (TreeNode): Parent node.
|
||||||
|
data (object): Data associated with the node.
|
||||||
|
"""
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
node._label = Text(f"{{}} {name}")
|
node._label = Text(f"{{}} {name}")
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
@@ -56,20 +63,24 @@ class TreeApp(App):
|
|||||||
add_node("JSON", node, json_data)
|
add_node("JSON", node, json_data)
|
||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
|
"""Load some JSON when the app starts."""
|
||||||
with open("food.json") as data_file:
|
with open("food.json") as data_file:
|
||||||
self.json_data = json.load(data_file)
|
self.json_data = json.load(data_file)
|
||||||
|
|
||||||
def action_add(self) -> None:
|
def action_add(self) -> None:
|
||||||
|
"""Add a node to the tree."""
|
||||||
tree = self.query_one(Tree)
|
tree = self.query_one(Tree)
|
||||||
json_node = tree.root.add("JSON")
|
json_node = tree.root.add("JSON")
|
||||||
self.add_json(json_node, self.json_data)
|
self.add_json(json_node, self.json_data)
|
||||||
tree.root.expand()
|
tree.root.expand()
|
||||||
|
|
||||||
def action_clear(self) -> None:
|
def action_clear(self) -> None:
|
||||||
|
"""Clear the tree (remove all nodes)."""
|
||||||
tree = self.query_one(Tree)
|
tree = self.query_one(Tree)
|
||||||
tree.clear()
|
tree.clear()
|
||||||
|
|
||||||
def action_toggle_root(self) -> None:
|
def action_toggle_root(self) -> None:
|
||||||
|
"""Toggle the root node."""
|
||||||
tree = self.query_one(Tree)
|
tree = self.query_one(Tree)
|
||||||
tree.show_root = not tree.show_root
|
tree.show_root = not tree.show_root
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "textual"
|
name = "textual"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
homepage = "https://github.com/Textualize/textual"
|
homepage = "https://github.com/Textualize/textual"
|
||||||
description = "Modern Text User Interface framework"
|
description = "Modern Text User Interface framework"
|
||||||
authors = ["Will McGugan <will@textualize.io>"]
|
authors = ["Will McGugan <will@textualize.io>"]
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ class DirEntry:
|
|||||||
|
|
||||||
|
|
||||||
class DirectoryTree(Tree[DirEntry]):
|
class DirectoryTree(Tree[DirEntry]):
|
||||||
|
"""A Tree widget that presents files and directories.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): Path to directory.
|
||||||
|
name (str | None, optional): The name of the widget, or None for no name. Defaults to None.
|
||||||
|
id (str | None, optional): The ID of the widget in the DOM, or None for no ID. Defaults to None.
|
||||||
|
classes (str | None, optional): A space-separated list of classes, or None for no classes. Defaults to None.
|
||||||
|
"""
|
||||||
|
|
||||||
COMPONENT_CLASSES: ClassVar[set[str]] = {
|
COMPONENT_CLASSES: ClassVar[set[str]] = {
|
||||||
"tree--label",
|
"tree--label",
|
||||||
@@ -68,6 +76,7 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
id: str | None = None,
|
id: str | None = None,
|
||||||
classes: str | None = None,
|
classes: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.path = path
|
self.path = path
|
||||||
super().__init__(
|
super().__init__(
|
||||||
path,
|
path,
|
||||||
|
|||||||
Reference in New Issue
Block a user