diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index 14801c039..7b33db8c8 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -365,6 +365,13 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True): TreeNode[EventTreeDataType]: The node that was collapsed. """ + class NodeHighlighted(NodeMessage[EventTreeDataType]): + """Event sent when a node is highlighted. + + Attributes: + TreeNode[EventTreeDataType]: The node that was collapsed. + """ + def __init__( self, label: TextType, @@ -573,6 +580,8 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True): self._refresh_node(node) node._selected = True self._cursor_node = node + if previous_node != node: + self.post_message_no_wait(self.NodeHighlighted(self, node)) def watch_guide_depth(self, guide_depth: int) -> None: self._invalidate() diff --git a/tests/tree/test_tree_messages.py b/tests/tree/test_tree_messages.py index 01a2f2645..ff2d8069c 100644 --- a/tests/tree/test_tree_messages.py +++ b/tests/tree/test_tree_messages.py @@ -32,6 +32,9 @@ class TreeApp(App[None]): def on_tree_node_collapsed(self, event: Tree.NodeCollapsed[None]) -> None: self.record(event) + def on_tree_node_highlighted(self, event: Tree.NodeHighlighted[None]) -> None: + self.record(event) + async def test_tree_node_selected_message() -> None: """Selecting a node should result in a selected message being emitted.""" @@ -57,3 +60,10 @@ async def test_tree_node_collapsed_message() -> None: "NodeCollapsed", "NodeSelected", ] + + +async def test_tree_node_highlighted_message() -> None: + """Highlighting a node should result in a highlighted message being emitted.""" + async with TreeApp().run_test() as pilot: + await pilot.press("enter", "down") + assert pilot.app.messages == ["NodeExpanded", "NodeSelected", "NodeHighlighted"]