mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge branch 'main' into multiselect
This commit is contained in:
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- `Placeholder.reset_color_cycle`
|
- `Placeholder.reset_color_cycle`
|
||||||
|
- Removed `Widget.reset_focus` (now called `Widget.blur`) https://github.com/Textualize/textual/issues/2642
|
||||||
|
|
||||||
|
|
||||||
## [0.26.0] - 2023-05-20
|
## [0.26.0] - 2023-05-20
|
||||||
|
|||||||
@@ -225,8 +225,8 @@ The main screen is darkened to indicate to the user that it is not active, and o
|
|||||||
It is a common requirement for screens to be able to return data.
|
It is a common requirement for screens to be able to return data.
|
||||||
For instance, you may want a screen to show a dialog and have the result of that dialog processed *after* the screen has been popped.
|
For instance, you may want a screen to show a dialog and have the result of that dialog processed *after* the screen has been popped.
|
||||||
|
|
||||||
To return data from a screen, call [`dismiss()`][textual.screen.dismiss] on the screen with the data you wish to return.
|
To return data from a screen, call [`dismiss()`][textual.screen.Screen.dismiss] on the screen with the data you wish to return.
|
||||||
This will pop the screen and invoke a callback set when the screen was pushed (with [`push_screen`][textual.app.push_screen]).
|
This will pop the screen and invoke a callback set when the screen was pushed (with [`push_screen`][textual.app.App.push_screen]).
|
||||||
|
|
||||||
Let's modify the previous example to use `dismiss` rather than an explicit `pop_screen`.
|
Let's modify the previous example to use `dismiss` rather than an explicit `pop_screen`.
|
||||||
|
|
||||||
|
|||||||
@@ -2075,7 +2075,7 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
Args:
|
Args:
|
||||||
widget: A Widget to unregister
|
widget: A Widget to unregister
|
||||||
"""
|
"""
|
||||||
widget.reset_focus()
|
widget.blur()
|
||||||
if isinstance(widget._parent, Widget):
|
if isinstance(widget._parent, Widget):
|
||||||
widget._parent._nodes._remove(widget)
|
widget._parent._nodes._remove(widget)
|
||||||
widget._detach()
|
widget._detach()
|
||||||
|
|||||||
@@ -1123,7 +1123,8 @@ class DOMNode(MessagePump):
|
|||||||
"""Replace all classes.
|
"""Replace all classes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
A string contain space separated classes, or an iterable of class names.
|
classes: A string containing space separated classes, or an
|
||||||
|
iterable of class names.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self.
|
Self.
|
||||||
|
|||||||
@@ -386,6 +386,7 @@ class Screen(Generic[ScreenResultType], Widget):
|
|||||||
focusable_widgets = self.focus_chain
|
focusable_widgets = self.focus_chain
|
||||||
if not focusable_widgets:
|
if not focusable_widgets:
|
||||||
# If there's nothing to focus... give up now.
|
# If there's nothing to focus... give up now.
|
||||||
|
self.set_focus(None)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -778,7 +779,7 @@ class Screen(Generic[ScreenResultType], Widget):
|
|||||||
def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> None:
|
def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> None:
|
||||||
"""Dismiss the screen, optionally with a result.
|
"""Dismiss the screen, optionally with a result.
|
||||||
|
|
||||||
If `result` is provided and a callback was set when the screen was [pushed][textual.app.push_screen], then
|
If `result` is provided and a callback was set when the screen was [pushed][textual.app.App.push_screen], then
|
||||||
the callback will be invoked with `result`.
|
the callback will be invoked with `result`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
@@ -2712,6 +2712,7 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
def watch_disabled(self) -> None:
|
def watch_disabled(self) -> None:
|
||||||
"""Update the styles of the widget and its children when disabled is toggled."""
|
"""Update the styles of the widget and its children when disabled is toggled."""
|
||||||
|
self.blur()
|
||||||
self._update_styles()
|
self._update_styles()
|
||||||
|
|
||||||
def _size_updated(
|
def _size_updated(
|
||||||
@@ -3017,8 +3018,10 @@ class Widget(DOMNode):
|
|||||||
self.app.call_later(set_focus, self)
|
self.app.call_later(set_focus, self)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def reset_focus(self) -> Self:
|
def blur(self) -> Self:
|
||||||
"""Reset the focus (move it to the next available widget).
|
"""Blur (un-focus) the widget.
|
||||||
|
|
||||||
|
Focus will be moved to the next available widget in the focus chain..
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The `Widget` instance.
|
The `Widget` instance.
|
||||||
@@ -3172,7 +3175,7 @@ class Widget(DOMNode):
|
|||||||
|
|
||||||
def _on_hide(self, event: events.Hide) -> None:
|
def _on_hide(self, event: events.Hide) -> None:
|
||||||
if self.has_focus:
|
if self.has_focus:
|
||||||
self.reset_focus()
|
self.blur()
|
||||||
|
|
||||||
def _on_scroll_to_region(self, message: messages.ScrollToRegion) -> None:
|
def _on_scroll_to_region(self, message: messages.ScrollToRegion) -> None:
|
||||||
self.scroll_to_region(message.region, animate=True)
|
self.scroll_to_region(message.region, animate=True)
|
||||||
|
|||||||
@@ -183,11 +183,6 @@ class Tabs(Widget, can_focus=True):
|
|||||||
ALLOW_SELECTOR_MATCH = {"tab"}
|
ALLOW_SELECTOR_MATCH = {"tab"}
|
||||||
"""Additional message attributes that can be used with the [`on` decorator][textual.on]."""
|
"""Additional message attributes that can be used with the [`on` decorator][textual.on]."""
|
||||||
|
|
||||||
tabs: Tabs
|
|
||||||
"""The tabs widget containing the tab."""
|
|
||||||
tab: Tab
|
|
||||||
"""The tab that was activated."""
|
|
||||||
|
|
||||||
def __init__(self, tabs: Tabs, tab: Tab) -> None:
|
def __init__(self, tabs: Tabs, tab: Tab) -> None:
|
||||||
"""Initialize event.
|
"""Initialize event.
|
||||||
|
|
||||||
@@ -195,8 +190,10 @@ class Tabs(Widget, can_focus=True):
|
|||||||
tabs: The Tabs widget.
|
tabs: The Tabs widget.
|
||||||
tab: The tab that was activated.
|
tab: The tab that was activated.
|
||||||
"""
|
"""
|
||||||
self.tabs = tabs
|
self.tabs: Tabs = tabs
|
||||||
self.tab = tab
|
"""The tabs widget containing the tab."""
|
||||||
|
self.tab: Tab = tab
|
||||||
|
"""The tab that was activated."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -215,16 +212,14 @@ class Tabs(Widget, can_focus=True):
|
|||||||
class Cleared(Message):
|
class Cleared(Message):
|
||||||
"""Sent when there are no active tabs."""
|
"""Sent when there are no active tabs."""
|
||||||
|
|
||||||
tabs: Tabs
|
|
||||||
"""The tabs widget which was cleared."""
|
|
||||||
|
|
||||||
def __init__(self, tabs: Tabs) -> None:
|
def __init__(self, tabs: Tabs) -> None:
|
||||||
"""Initialize the event.
|
"""Initialize the event.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tabs: The tabs widget.
|
tabs: The tabs widget.
|
||||||
"""
|
"""
|
||||||
self.tabs = tabs
|
self.tabs: Tabs = tabs
|
||||||
|
"""The tabs widget which was cleared."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
20
tests/snapshot_tests/snapshot_apps/blur_on_disabled.py
Normal file
20
tests/snapshot_tests/snapshot_apps/blur_on_disabled.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.widgets import Input
|
||||||
|
|
||||||
|
|
||||||
|
class BlurApp(App):
|
||||||
|
BINDINGS = [("f3", "disable")]
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
yield Input()
|
||||||
|
|
||||||
|
def on_ready(self) -> None:
|
||||||
|
self.query_one(Input).focus()
|
||||||
|
|
||||||
|
def action_disable(self) -> None:
|
||||||
|
self.query_one(Input).disabled = True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = BlurApp()
|
||||||
|
app.run()
|
||||||
@@ -514,3 +514,11 @@ def test_select_rebuild(snap_compare):
|
|||||||
SNAPSHOT_APPS_DIR / "select_rebuild.py",
|
SNAPSHOT_APPS_DIR / "select_rebuild.py",
|
||||||
press=["space", "escape", "tab", "enter", "tab", "space"],
|
press=["space", "escape", "tab", "enter", "tab", "space"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_blur_on_disabled(snap_compare):
|
||||||
|
# https://github.com/Textualize/textual/issues/2641
|
||||||
|
assert snap_compare(
|
||||||
|
SNAPSHOT_APPS_DIR / "blur_on_disabled.py",
|
||||||
|
press=[*"foo", "f3", *"this should not appear"],
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user