Skip to content

Commit edaf393

Browse files
committed
Merge branch 'main' into bookmarking
* main: fix(textarea-autoresize): add a bit of padding when setting textarea height (#1891) Properly send custom message in a synchronous manner (#1888) fix(page-main-container): Fillable container with min-height/width only when parent layout is fillable (#1885) Add `.latest_stream` to `ui.MarkdownStream()` and deprecate `.get_latest_stream_result()` (#1884)
2 parents a6d3149 + 1ff586f commit edaf393

File tree

20 files changed

+87
-54
lines changed

20 files changed

+87
-54
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to Shiny for Python will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [UNRELEASED]
9+
10+
### Changes
11+
12+
* The `.get_latest_stream_result()` method on `ui.MarkdownStream()` was deprecated in favor of the new `.latest_stream` property. Call `.result()` on the property to get the latest result, `.status` to check the status, and `.cancel()` to cancel the stream.
13+
14+
### Bug fixes
15+
16+
* Fixed an issue where the `<main>` areas of `ui.page_sidebar()` and `ui.page_navbar()` (with a `sidebar`) were made to be a fillable containers even when `fillable=False`. (#1816)
17+
18+
* Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891)
19+
820
## [1.3.0] - 2025-03-03
921

1022
### New features

js/chat/chat.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ shiny-chat-container {
3232
text-underline-offset: 4px;
3333
text-decoration-thickness: 2px;
3434

35-
padding: 2px;
35+
padding-inline: 2px;
3636

3737
&:hover {
3838
text-decoration-style: solid;

js/text-area/textarea-autoresize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function update_height(target: HTMLTextAreaElement) {
4949
if (target.scrollHeight > 0) {
5050
// Automatically resize the textarea to fit its content.
5151
target.style.height = "auto";
52-
target.style.height = target.scrollHeight + "px";
52+
target.style.height = target.scrollHeight + 2 + "px";
5353
} else {
5454
// The textarea is not visible on the page, therefore it has a 0 scroll height.
5555

scripts/_pkg-sources.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
list(
2-
bslib = "rstudio/bslib@main",
2+
bslib = "rstudio/bslib@fix/page-main-container-fillable",
33
shiny = "rstudio/shiny@main",
44
sass = "sass",
55
htmltools = "rstudio/htmltools@main"

shiny/ui/_chat.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,16 +1107,13 @@ def update_user_input(
11071107
}
11081108
)
11091109

1110-
_utils.run_coro_sync(
1111-
self._session.send_custom_message(
1112-
"shinyChatMessage",
1113-
{
1114-
"id": self.id,
1115-
"handler": "shiny-chat-update-user-input",
1116-
"obj": obj,
1117-
},
1118-
)
1119-
)
1110+
msg = {
1111+
"id": self.id,
1112+
"handler": "shiny-chat-update-user-input",
1113+
"obj": obj,
1114+
}
1115+
1116+
self._session._send_message_sync({"custom": {"shinyChatMessage": msg}})
11201117

11211118
def set_user_message(self, value: str):
11221119
"""

shiny/ui/_markdown_stream.py

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from htmltools import css
55

66
from .. import _utils, reactive
7+
from .._deprecated import warn_deprecated
78
from .._docstring import add_example
89
from .._namespaces import resolve_id
910
from .._typing_extensions import TypedDict
@@ -87,9 +88,14 @@ def __init__(
8788
self.on_error = on_error
8889

8990
with session_context(self._session):
90-
self._latest_stream: reactive.Value[
91-
Union[reactive.ExtendedTask[[], str], None]
92-
] = reactive.Value(None)
91+
92+
@reactive.extended_task
93+
async def _mock_task() -> str:
94+
return ""
95+
96+
self._latest_stream: reactive.Value[reactive.ExtendedTask[[], str]] = (
97+
reactive.Value(_mock_task)
98+
)
9399

94100
async def stream(
95101
self,
@@ -151,32 +157,46 @@ async def _handle_error():
151157

152158
return _task
153159

154-
def get_latest_stream_result(self) -> Union[str, None]:
160+
@property
161+
def latest_stream(self):
155162
"""
156-
Reactively read the latest stream result.
163+
React to changes in the latest stream.
164+
165+
Reactively reads for the :class:`~shiny.reactive.ExtendedTask` behind the
166+
latest stream.
157167
158-
This method reads a reactive value containing the result of the latest
159-
`.stream()`. Therefore, this method must be called in a reactive context (e.g.,
160-
a render function, a :func:`~shiny.reactive.calc`, or a
161-
:func:`~shiny.reactive.effect`).
168+
From the return value (i.e., the extended task), you can then:
169+
170+
1. Reactively read for the final `.result()`.
171+
2. `.cancel()` the stream.
172+
3. Check the `.status()` of the stream.
162173
163174
Returns
164175
-------
165176
:
166-
The result of the latest stream (a string).
177+
An extended task that represents the streaming task. The `.result()` method
178+
of the task can be called in a reactive context to get the final state of the
179+
stream.
167180
168-
Raises
169-
------
170-
:
171-
A silent exception if no stream has completed yet.
181+
Note
182+
----
183+
If no stream has yet been started when this method is called, then it returns an
184+
extended task with `.status()` of `"initial"` and that it status doesn't change
185+
state until a message is streamed.
172186
"""
173-
stream = self._latest_stream()
174-
if stream is None:
175-
from .. import req
187+
return self._latest_stream()
176188

177-
req(False)
178-
else:
179-
return stream.result()
189+
def get_latest_stream_result(self) -> Union[str, None]:
190+
"""
191+
Reactively read the latest stream result.
192+
193+
Deprecated. Use `latest_stream.result()` instead.
194+
"""
195+
warn_deprecated(
196+
"The `.get_latest_stream_result()` method is deprecated and will be removed "
197+
"in a future release. Use `.latest_stream.result()` instead. "
198+
)
199+
self.latest_stream.result()
180200

181201
async def clear(self):
182202
"""

shiny/ui/_navs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,9 @@ def layout(self, nav: Tag, content: Tag) -> TagList:
13651365
# TODO-future: This could also be applied to the non-sidebar page layout above
13661366
from ._page import page_main_container
13671367

1368-
tab_content = page_main_container(*contents)
1368+
tab_content = page_main_container(
1369+
*contents, fillable=self.fillable is not False
1370+
)
13691371

13701372
content_div = div(
13711373
# In the fluid case, the sidebar layout should be flush (i.e.,

shiny/ui/_page.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def page_sidebar(
134134
navbar_title,
135135
layout_sidebar(
136136
sidebar,
137-
page_main_container(*children),
137+
page_main_container(*children, fillable=fillable),
138138
attrs,
139139
fillable=fillable,
140140
border=False,
@@ -149,8 +149,10 @@ def page_sidebar(
149149
)
150150

151151

152-
def page_main_container(*args: TagChild) -> Tag:
152+
def page_main_container(*args: TagChild, fillable: bool = True) -> Tag:
153153
main = tags.main({"class": "bslib-page-main bslib-gap-spacing"}, *args)
154+
if not fillable:
155+
return main
154156
return as_fillable_container(as_fill_item(main))
155157

156158

shiny/www/py-shiny/chat/chat.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)