Skip to content

Commit c86ec1e

Browse files
committed
Merge branch 'main' into machow-feat-narwhals
* main: bug(input_text_area): Auto resized text areas resize on visibility change (posit-dev#1569) chore(ci): Skip all chat tests on webkit (posit-dev#1575)
2 parents 81058ea + 97dd4a7 commit c86ec1e

File tree

12 files changed

+155
-5
lines changed

12 files changed

+155
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919

2020
* Require shinyswatch >= 0.7.0 and updated examples accordingly. (#1558)
2121

22+
* `input_text_area(autoresize=True)` now resizes properly even when it's not visible when initially rendered (e.g. in a closed accordion or a hidden tab). (#1560)
23+
2224
### Bug fixes
2325

2426
### Deprecations

js/text-area/textarea-autoresize.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,46 @@ function onDelegatedEvent(
1818
});
1919
}
2020

21+
// Use a single intersectionObserver as they are slow to create / use.
22+
let textAreaIntersectionObserver: null | IntersectionObserver = null;
23+
24+
function callUpdateHeightWhenTargetIsVisible(target: HTMLTextAreaElement) {
25+
if (textAreaIntersectionObserver === null) {
26+
// Create a single observer to watch for the textarea becoming visible
27+
textAreaIntersectionObserver = new IntersectionObserver(
28+
(entries, observer) => {
29+
entries.forEach((entry) => {
30+
// Quit if the entry is not visible
31+
if (!entry.isIntersecting) {
32+
return;
33+
}
34+
// If the entry is visible (even if it's just a single pixel)
35+
// Stop observing the target
36+
textAreaIntersectionObserver!.unobserve(entry.target);
37+
38+
// Update the height of the textarea
39+
update_height(entry.target as HTMLTextAreaElement);
40+
});
41+
}
42+
);
43+
}
44+
45+
textAreaIntersectionObserver.observe(target);
46+
}
47+
2148
function update_height(target: HTMLTextAreaElement) {
22-
// Automatically resize the textarea to fit its content.
23-
target.style.height = "auto";
24-
target.style.height = target.scrollHeight + "px";
49+
if (target.scrollHeight > 0) {
50+
// Automatically resize the textarea to fit its content.
51+
target.style.height = "auto";
52+
target.style.height = target.scrollHeight + "px";
53+
} else {
54+
// The textarea is not visible on the page, therefore it has a 0 scroll height.
55+
56+
// If we should autoresize the text area height, then we can wait for the textarea to
57+
// become visible and call `update_height` again. Hopefully the scroll height is no
58+
// longer 0
59+
callUpdateHeightWhenTargetIsVisible(target);
60+
}
2561
}
2662

2763
// Update on change

shiny/www/py-shiny/text-area/textarea-autoresize.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,30 @@ function onDelegatedEvent(eventName, selector, callback) {
77
}
88
});
99
}
10+
var textAreaIntersectionObserver = null;
11+
function callUpdateHeightWhenTargetIsVisible(target) {
12+
if (textAreaIntersectionObserver === null) {
13+
textAreaIntersectionObserver = new IntersectionObserver(
14+
(entries, observer) => {
15+
entries.forEach((entry) => {
16+
if (!entry.isIntersecting) {
17+
return;
18+
}
19+
textAreaIntersectionObserver.unobserve(entry.target);
20+
update_height(entry.target);
21+
});
22+
}
23+
);
24+
}
25+
textAreaIntersectionObserver.observe(target);
26+
}
1027
function update_height(target) {
11-
target.style.height = "auto";
12-
target.style.height = target.scrollHeight + "px";
28+
if (target.scrollHeight > 0) {
29+
target.style.height = "auto";
30+
target.style.height = target.scrollHeight + "px";
31+
} else {
32+
callUpdateHeightWhenTargetIsVisible(target);
33+
}
1334
}
1435
onDelegatedEvent(
1536
"input",

tests/playwright/shiny/components/chat/append_user_msg/test_chat_append_user_msg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
23

34
from shiny.playwright import controller
45
from shiny.run import ShinyAppProc
56

67

8+
@skip_on_webkit
79
def test_validate_chat_append_user_message(page: Page, local_app: ShinyAppProc) -> None:
810
page.goto(local_app.url)
911

tests/playwright/shiny/components/chat/basic/test_chat_basic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
23

34
from shiny.playwright import controller
45
from shiny.run import ShinyAppProc
56

67

8+
@skip_on_webkit
79
def test_validate_chat_basic(page: Page, local_app: ShinyAppProc) -> None:
810
page.goto(local_app.url)
911

tests/playwright/shiny/components/chat/errors/test_chat_errors.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
23

34
from shiny.playwright import controller
45
from shiny.run import ShinyAppProc
56

67

8+
@skip_on_webkit
79
def test_validate_chat_basic_error(page: Page, local_app: ShinyAppProc) -> None:
810
page.goto(local_app.url)
911

tests/playwright/shiny/components/chat/stream/test_chat_stream.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import re
22

33
from playwright.sync_api import Page, expect
4+
from utils.deploy_utils import skip_on_webkit
45

56
from shiny.playwright import controller
67
from shiny.run import ShinyAppProc
78

89

10+
@skip_on_webkit
911
def test_validate_chat(page: Page, local_app: ShinyAppProc) -> None:
1012
page.goto(local_app.url)
1113

tests/playwright/shiny/components/chat/transform/test_chat_transform.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
23

34
from shiny.playwright import controller
45
from shiny.run import ShinyAppProc
56

67

8+
@skip_on_webkit
79
def test_validate_chat_transform(page: Page, local_app: ShinyAppProc) -> None:
810
page.goto(local_app.url)
911

tests/playwright/shiny/components/chat/transform_assistant/test_chat_transform_assistant.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
23

34
from shiny import ui
45
from shiny.playwright import controller
56
from shiny.run import ShinyAppProc
67

78

9+
@skip_on_webkit
810
def test_validate_chat_transform_assistant(page: Page, local_app: ShinyAppProc) -> None:
911
page.goto(local_app.url)
1012

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from shiny.express import render, ui
2+
3+
with ui.navset_card_tab(id="tab"):
4+
5+
with ui.nav_panel("Tab 1"):
6+
"Tab 1 content"
7+
with ui.nav_panel("Text Area"):
8+
ui.input_text_area(
9+
id="test_text_area",
10+
label="A text area input",
11+
autoresize=True,
12+
value="a\nb\nc\nd\ne",
13+
)
14+
15+
ui.input_text_area(
16+
id="test_text_area2",
17+
label="A second text area input",
18+
autoresize=True,
19+
value="a\nb\nc\nd\ne",
20+
rows=4,
21+
)
22+
23+
24+
@render.code
25+
def text():
26+
return "Loaded"

0 commit comments

Comments
 (0)