mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
shutdown scrollbas
This commit is contained in:
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [0.2.2] - Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue where scrollbars weren't being unmounted
|
||||
|
||||
### Changed
|
||||
|
||||
- DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
|
||||
@@ -19,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Added App.run_async method
|
||||
- Added App.run_test context manager
|
||||
- Added auto_pilot to App.run and App.run_async
|
||||
- Added Widget._get_virtual_dom to get scrollbars
|
||||
|
||||
## [0.2.1] - 2022-10-23
|
||||
|
||||
|
||||
18
sandbox/will/scroll_remove.py
Normal file
18
sandbox/will/scroll_remove.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from textual.app import App, ComposeResult
|
||||
|
||||
from textual.containers import Container
|
||||
|
||||
|
||||
class ScrollApp(App):
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Container(
|
||||
Container(), Container(),
|
||||
id="top")
|
||||
|
||||
def key_r(self) -> None:
|
||||
self.query_one("#top").remove()
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = ScrollApp()
|
||||
app.run()
|
||||
@@ -1605,9 +1605,6 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
await self._prune_node(widget)
|
||||
|
||||
# for child in remove_widgets:
|
||||
# await child._close_messages()
|
||||
# self._unregister(child)
|
||||
if parent is not None:
|
||||
parent.refresh(layout=True)
|
||||
|
||||
@@ -1625,7 +1622,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
while stack:
|
||||
widget = pop()
|
||||
if widget.children:
|
||||
yield list(widget.children)
|
||||
yield [*widget.children, *widget._get_virtual_dom()]
|
||||
for child in widget.children:
|
||||
push(child)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import click
|
||||
from importlib_metadata import version
|
||||
|
||||
from textual.pilot import Pilot
|
||||
from textual._import_app import import_app, AppFail
|
||||
|
||||
|
||||
@@ -84,7 +85,12 @@ def run_app(import_name: str, dev: bool, press: str) -> None:
|
||||
sys.exit(1)
|
||||
|
||||
press_keys = press.split(",") if press else None
|
||||
result = app.run(press=press_keys)
|
||||
|
||||
async def run_press_keys(pilot: Pilot) -> None:
|
||||
if press_keys is not None:
|
||||
await pilot.press(*press_keys)
|
||||
|
||||
result = app.run(auto_pilot=run_press_keys)
|
||||
|
||||
if result is not None:
|
||||
from rich.console import Console
|
||||
|
||||
@@ -359,6 +359,20 @@ class Widget(DOMNode):
|
||||
"""Clear arrangement cache, forcing a new arrange operation."""
|
||||
self._arrangement = None
|
||||
|
||||
def _get_virtual_dom(self) -> Iterable[Widget]:
|
||||
"""Get widgets not part of the DOM.
|
||||
|
||||
Returns:
|
||||
Iterable[Widget]: An iterable of Widgets.
|
||||
|
||||
"""
|
||||
if self._horizontal_scrollbar is not None:
|
||||
yield self._horizontal_scrollbar
|
||||
if self._vertical_scrollbar is not None:
|
||||
yield self._vertical_scrollbar
|
||||
if self._scrollbar_corner is not None:
|
||||
yield self._scrollbar_corner
|
||||
|
||||
def mount(self, *anon_widgets: Widget, **widgets: Widget) -> AwaitMount:
|
||||
"""Mount child widgets (making this widget a container).
|
||||
|
||||
@@ -587,6 +601,7 @@ class Widget(DOMNode):
|
||||
Returns:
|
||||
ScrollBar: ScrollBar Widget.
|
||||
"""
|
||||
|
||||
from .scrollbar import ScrollBar
|
||||
|
||||
if self._horizontal_scrollbar is not None:
|
||||
@@ -600,7 +615,7 @@ class Widget(DOMNode):
|
||||
|
||||
def _refresh_scrollbars(self) -> None:
|
||||
"""Refresh scrollbar visibility."""
|
||||
if not self.is_scrollable:
|
||||
if not self.is_scrollable or not self.container_size:
|
||||
return
|
||||
|
||||
styles = self.styles
|
||||
|
||||
23
tests/test_auto_pilot.py
Normal file
23
tests/test_auto_pilot.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from textual.app import App
|
||||
from textual.pilot import Pilot
|
||||
from textual import events
|
||||
|
||||
|
||||
def test_auto_pilot() -> None:
|
||||
|
||||
keys_pressed: list[str] = []
|
||||
|
||||
class TestApp(App):
|
||||
def on_key(self, event: events.Key) -> None:
|
||||
keys_pressed.append(event.key)
|
||||
|
||||
async def auto_pilot(pilot: Pilot) -> None:
|
||||
|
||||
await pilot.press("tab", *"foo")
|
||||
await pilot.pause(1 / 100)
|
||||
await pilot.exit("bar")
|
||||
|
||||
app = TestApp()
|
||||
result = app.run(headless=True, auto_pilot=auto_pilot)
|
||||
assert result == "bar"
|
||||
assert keys_pressed == ["tab", "f", "o", "o"]
|
||||
21
tests/test_test_runner.py
Normal file
21
tests/test_test_runner.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from textual.app import App
|
||||
from textual import events
|
||||
|
||||
|
||||
async def test_run_test() -> None:
|
||||
"""Test the run_test context manager."""
|
||||
keys_pressed: list[str] = []
|
||||
|
||||
class TestApp(App[str]):
|
||||
def on_key(self, event: events.Key) -> None:
|
||||
keys_pressed.append(event.key)
|
||||
|
||||
app = TestApp()
|
||||
async with app.run_test() as pilot:
|
||||
assert str(pilot) == "<Pilot app=TestApp(title='TestApp')>"
|
||||
await pilot.press("tab", *"foo")
|
||||
await pilot.pause(1 / 100)
|
||||
await pilot.exit("bar")
|
||||
|
||||
assert app.return_value == "bar"
|
||||
assert keys_pressed == ["tab", "f", "o", "o"]
|
||||
Reference in New Issue
Block a user