Skip to content

Commit 6b1e24d

Browse files
committed
More aggressively update scrollable element. Add test for obtaining streaming result
1 parent 5089b99 commit 6b1e24d

File tree

5 files changed

+56
-25
lines changed

5 files changed

+56
-25
lines changed

js/markdown-stream/markdown-stream.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,24 +92,24 @@ class MarkdownElement extends LightElement {
9292
protected willUpdate(changedProperties: PropertyValues): void {
9393
if (changedProperties.has("content")) {
9494
this.#isContentBeingAdded = true;
95-
// A scrollable element might not be available until the content
96-
// grows to a certain size. So, keep looking for it until it's found.
97-
if (!this.#scrollableElement) this.#updateScrollableElement();
98-
}
99-
if (changedProperties.has("streaming")) {
100-
this.#updateScrollableElement();
10195
}
96+
super.willUpdate(changedProperties);
10297
}
10398

10499
protected updated(changedProperties: Map<string, unknown>): void {
105100
if (changedProperties.has("content")) {
101+
// Post-process DOM after content has been added
106102
try {
107103
this.#highlightAndCodeCopy();
108104
} catch (error) {
109105
console.warn("Failed to highlight code:", error);
110106
}
111-
112107
if (this.streaming) this.#appendStreamingDot();
108+
109+
// Update scrollable element after content has been added
110+
this.#updateScrollableElement();
111+
112+
// Possibly scroll to bottom after content has been added
113113
this.#isContentBeingAdded = false;
114114
this.#maybeScrollToBottom();
115115
}

shiny/www/py-shiny/markdown-stream/markdown-stream.js

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

shiny/www/py-shiny/markdown-stream/markdown-stream.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/playwright/shiny/components/MarkdownStream/basic/app.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import asyncio
12
from pathlib import Path
23

34
from shiny import reactive
4-
from shiny.express import ui
5+
from shiny.express import render, ui
56

67
# Read in the py-shiny README.md file
78
readme = Path(__file__).parent / "README.md"
@@ -10,11 +11,12 @@
1011

1112

1213
stream = ui.MarkdownStream("shiny-readme")
13-
stream2 = ui.MarkdownStream("shiny-readme-err")
14+
stream_err = ui.MarkdownStream("shiny-readme-err")
1415

1516

16-
def readme_generator():
17+
async def readme_generator():
1718
for chunk in readme_chunks:
19+
await asyncio.sleep(0.02)
1820
yield chunk + " "
1921

2022

@@ -28,7 +30,7 @@ def readme_generator_err():
2830
@reactive.effect
2931
async def _():
3032
await stream.stream(readme_generator())
31-
await stream2.stream(readme_generator_err())
33+
await stream_err.stream(readme_generator_err())
3234

3335

3436
with ui.card(
@@ -41,4 +43,29 @@ async def _():
4143

4244
with ui.card(class_="mt-3"):
4345
ui.card_header("Shiny README.md with error")
44-
stream2.ui()
46+
stream_err.ui()
47+
48+
49+
basic_stream = ui.MarkdownStream("basic-stream-result")
50+
basic_stream.ui()
51+
52+
53+
def basic_generator():
54+
yield "Basic "
55+
yield "stream"
56+
57+
58+
@reactive.calc
59+
async def stream_task():
60+
return await basic_stream.stream(basic_generator())
61+
62+
63+
@reactive.effect
64+
async def _():
65+
await stream_task()
66+
67+
68+
@render.text
69+
async def stream_result():
70+
task = await stream_task()
71+
return f"Stream result: {task.result()}"

tests/playwright/shiny/components/MarkdownStream/basic/test_stream_basic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from playwright.sync_api import Page, expect
22

3+
from shiny.playwright import controller
34
from shiny.run import ShinyAppProc
45

56

@@ -43,3 +44,6 @@ def test_validate_stream_basic(page: Page, local_app: ShinyAppProc) -> None:
4344
notification = page.locator(".shiny-notification-error")
4445
expect(notification).to_be_visible(timeout=30 * 1000)
4546
expect(notification).to_contain_text("boom!")
47+
48+
txt_result = controller.OutputText(page, "basic-stream-result")
49+
txt_result.expect_value("Stream result: Basic stream")

0 commit comments

Comments
 (0)