fix refresh on remove (#2008)

* fix refresh on remove

* changelog

* optimization

* added snapshot
This commit is contained in:
Will McGugan
2023-03-10 10:06:10 +00:00
committed by GitHub
parent e2c36c4a15
commit d3bdaf8ae5
7 changed files with 221 additions and 7 deletions

View File

@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Fixed
- Fixed container not resizing when a widget is removed https://github.com/Textualize/textual/issues/2007
## [0.14.0] - 2023-03-09
### Changed

View File

@@ -2175,7 +2175,7 @@ class App(Generic[ReturnType], DOMNode):
for child in widget._nodes:
push(child)
def _remove_nodes(self, widgets: list[Widget]) -> AwaitRemove:
def _remove_nodes(self, widgets: list[Widget], parent: DOMNode) -> AwaitRemove:
"""Remove nodes from DOM, and return an awaitable that awaits cleanup.
Args:
@@ -2198,7 +2198,8 @@ class App(Generic[ReturnType], DOMNode):
await self._prune_nodes(widgets)
finally:
finished_event.set()
self.refresh(layout=True)
if parent.styles.auto_dimensions:
parent.refresh(layout=True)
removed_widgets = self._detach_from_dom(widgets)

View File

@@ -355,7 +355,7 @@ class DOMQuery(Generic[QueryType]):
An awaitable object that waits for the widgets to be removed.
"""
app = active_app.get()
await_remove = app._remove_nodes(list(self))
await_remove = app._remove_nodes(list(self), self._node)
return await_remove
def set_styles(

View File

@@ -2548,7 +2548,7 @@ class Widget(DOMNode):
An awaitable object that waits for the widget to be removed.
"""
await_remove = self.app._remove_nodes([self])
await_remove = self.app._remove_nodes([self], self.parent)
return await_remove
def render(self) -> RenderableType:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,38 @@
from textual.app import App, ComposeResult
from textual.containers import Vertical
from textual.widgets import Header, Footer, Label
class VerticalRemoveApp(App[None]):
CSS = """
Vertical {
border: round green;
height: auto;
}
Label {
border: round yellow;
background: red;
color: yellow;
}
"""
BINDINGS = [
("a", "add", "Add"),
("d", "del", "Delete"),
]
def compose(self) -> ComposeResult:
yield Header()
yield Vertical()
yield Footer()
def action_add(self) -> None:
self.query_one(Vertical).mount(Label("This is a test label"))
def action_del(self) -> None:
if self.query_one(Vertical).children:
self.query_one(Vertical).children[-1].remove()
if __name__ == "__main__":
VerticalRemoveApp().run()

View File

@@ -170,9 +170,11 @@ def test_content_switcher_example_initial(snap_compare):
def test_content_switcher_example_switch(snap_compare):
assert snap_compare(WIDGET_EXAMPLES_DIR / "content_switcher.py", press=[
"tab", "tab", "enter", "wait:500"
], terminal_size=(50, 50))
assert snap_compare(
WIDGET_EXAMPLES_DIR / "content_switcher.py",
press=["tab", "tab", "enter", "wait:500"],
terminal_size=(50, 50),
)
# --- CSS properties ---
@@ -234,6 +236,7 @@ def test_programmatic_scrollbar_gutter_change(snap_compare):
# --- CLI Preview Apps ---
# For our CLI previews e.g. `textual easing`, `textual colors` etc, we have snapshots
def test_borders_preview(snap_compare):
assert snap_compare(CLI_PREVIEWS_DIR / "borders.py", press=["tab", "enter"])
@@ -296,3 +299,9 @@ def test_focus_component_class(snap_compare):
def test_line_api_scrollbars(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "line_api_scrollbars.py")
def test_remove_with_auto_height(snap_compare):
assert snap_compare(
SNAPSHOT_APPS_DIR / "remove_auto.py", press=["a", "a", "a", "d", "d"]
)