Skip to content

Commit

Permalink
fix(select): watch reactive prompt change (#3701)
Browse files Browse the repository at this point in the history
* fix(select): allow reactive prompt change

* update watcher with new is_mounted check

* update only first in option list

* update option list only if allow blank

* update changelog
  • Loading branch information
TomJGooding authored Nov 27, 2023
1 parent 9a9a072 commit d8b0583
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Loading indicators and app notifications overlapped in the wrong order https://github.com/Textualize/textual/issues/3677
- Widgets being loaded are disabled and have their scrolling explicitly disabled too https://github.com/Textualize/textual/issues/3677
- Method render on a widget could be called before mounting said widget https://github.com/Textualize/textual/issues/2914
- Fixed `Select` not updating after changing the `prompt` reactive https://github.com/Textualize/textual/issues/2983

### Added

Expand Down
12 changes: 12 additions & 0 deletions src/textual/widgets/_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,15 @@ def clear(self) -> None:
raise InvalidSelectValueError(
"Can't clear selection if allow_blank is set to False."
) from None

def _watch_prompt(self, prompt: str) -> None:
if not self.is_mounted:
return
select_current = self.query_one(SelectCurrent)
select_current.placeholder = prompt
if not self._allow_blank:
return
if self.value == self.BLANK:
select_current.update(self.BLANK)
option_list = self.query_one(SelectOverlay)
option_list.replace_option_prompt_at_index(0, Text(prompt, style="dim"))
54 changes: 54 additions & 0 deletions tests/select/test_prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from rich.text import Text

from textual.app import App
from textual.widgets import Select, Static
from textual.widgets._select import SelectCurrent, SelectOverlay


async def test_reactive_prompt_change():
"""Regression test for https://github.com/Textualize/textual/issues/2983"""

class SelectApp(App):
def compose(self):
yield Select[int](
[(str(n), n) for n in range(3)],
prompt="Old prompt",
)

app = SelectApp()
async with app.run_test() as pilot:
select_widget = pilot.app.query_one(Select)
select_current = select_widget.query_one(SelectCurrent)
select_current_label = select_current.query_one("#label", Static)
select_overlay = select_widget.query_one(SelectOverlay)

assert select_current_label.renderable == Text("Old prompt")
assert select_overlay._options[0].prompt == Text("Old prompt")

select_widget.prompt = "New prompt"
assert select_current_label.renderable == Text("New prompt")
assert select_overlay._options[0].prompt == Text("New prompt")


async def test_reactive_prompt_change_when_allow_blank_is_false():
class SelectApp(App):
def compose(self):
yield Select[int](
[(str(n), n) for n in range(3)],
prompt="Old prompt",
allow_blank=False,
)

app = SelectApp()
async with app.run_test() as pilot:
select_widget = pilot.app.query_one(Select)
select_current = select_widget.query_one(SelectCurrent)
select_current_label = select_current.query_one("#label", Static)
select_overlay = select_widget.query_one(SelectOverlay)

assert select_current_label.renderable == Text("0")
assert select_overlay._options[0].prompt == "0"

select_widget.prompt = "New prompt"
assert select_current_label.renderable == Text("0")
assert select_overlay._options[0].prompt == "0"

0 comments on commit d8b0583

Please sign in to comment.