Skip to content

Commit 58db719

Browse files
committed
Merge branch 'main' into fix/chat-content-change-handler
2 parents 3dc26bd + bc07d2c commit 58db719

File tree

6 files changed

+57
-14
lines changed

6 files changed

+57
-14
lines changed

.github/workflows/verify-js-built.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
run: |
4040
if [[ `git status --porcelain` ]]; then
4141
git diff
42-
echo "Uncommitted changes found. Please commit any changes that result from 'npm run build'."
42+
echo "Uncommitted changes found. Please commit any changes that result from 'npm ci && npm run build'."
4343
exit 1
4444
else
4545
echo "No uncommitted changes found."

js/chat/chat.scss

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ shiny-chat-container {
33
--shiny-chat-user-message-bg: RGBA(var(--bs-primary-rgb, 0, 123, 194), 0.06);
44
--_chat-container-padding: 0.25rem;
55

6-
display: flex;
7-
flex-direction: column;
6+
display: grid;
7+
grid-template-columns: 1fr;
8+
grid-template-rows: 1fr auto;
89
margin: 0 auto;
9-
gap: 1rem;
10-
overflow: auto;
10+
gap: 0;
1111
padding: var(--_chat-container-padding);
1212
padding-bottom: 0; // Bottom padding is on input element
1313

@@ -54,6 +54,13 @@ shiny-chat-messages {
5454
display: flex;
5555
flex-direction: column;
5656
gap: 2rem;
57+
overflow: auto;
58+
margin-bottom: 1rem;
59+
60+
// Make space for the scroll bar
61+
--_scroll-margin: 1rem;
62+
padding-right: var(--_scroll-margin);
63+
margin-right: calc(-1 * var(--_scroll-margin));
5764
}
5865

5966
shiny-chat-message {
@@ -96,13 +103,12 @@ shiny-chat-message {
96103
}
97104

98105
shiny-chat-input {
99-
--_input-padding-top: 1rem;
106+
--_input-padding-top: 0;
100107
--_input-padding-bottom: var(--_chat-container-padding, 0.25rem);
101108

102-
margin-top: auto;
109+
margin-top: calc(-1 * var(--_input-padding-top));
103110
position: sticky;
104-
bottom: 0;
105-
background: linear-gradient(to bottom, transparent, var(--bs-body-bg, white) calc(var(--_input-padding-top) - var(--_input-padding-bottom)));
111+
bottom: calc(-1 * var(--_input-padding-bottom));
106112
padding-block: var(--_input-padding-top) var(--_input-padding-bottom);
107113

108114
textarea {

js/chat/chat.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ class ChatInput extends LightElement {
262262
}
263263

264264
class ChatContainer extends LightElement {
265+
<<<<<<< HEAD
266+
=======
267+
inputSentinelObserver?: IntersectionObserver;
268+
269+
>>>>>>> main
265270
private get input(): ChatInput {
266271
return this.querySelector(CHAT_INPUT_TAG) as ChatInput;
267272
}
@@ -279,6 +284,35 @@ class ChatContainer extends LightElement {
279284
return html``;
280285
}
281286

287+
connectedCallback(): void {
288+
super.connectedCallback();
289+
290+
// We use a sentinel element that we place just above the shiny-chat-input. When it
291+
// moves off-screen we know that the text area input is now floating, add shadow.
292+
let sentinel = this.querySelector<HTMLElement>("div");
293+
if (!sentinel) {
294+
sentinel = createElement("div", {
295+
style: "width: 100%; height: 0;",
296+
}) as HTMLElement;
297+
this.input.insertAdjacentElement("afterend", sentinel);
298+
}
299+
300+
this.inputSentinelObserver = new IntersectionObserver(
301+
(entries) => {
302+
const inputTextarea = this.input.querySelector("textarea");
303+
if (!inputTextarea) return;
304+
const addShadow = entries[0]?.intersectionRatio === 0;
305+
inputTextarea.classList.toggle("shadow", addShadow);
306+
},
307+
{
308+
threshold: [0, 1],
309+
rootMargin: "0px",
310+
}
311+
);
312+
313+
this.inputSentinelObserver.observe(sentinel);
314+
}
315+
282316
firstUpdated(): void {
283317
// Don't attach event listeners until child elements are rendered
284318
if (!this.messages) return;
@@ -305,6 +339,9 @@ class ChatContainer extends LightElement {
305339
disconnectedCallback(): void {
306340
super.disconnectedCallback();
307341

342+
this.inputSentinelObserver?.disconnect();
343+
this.inputSentinelObserver = undefined;
344+
308345
this.removeEventListener("shiny-chat-input-sent", this.#onInputSent);
309346
this.removeEventListener("shiny-chat-append-message", this.#onAppend);
310347
this.removeEventListener(

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ dev = [
117117
"google-generativeai;python_version>='3.9'",
118118
"langchain_core",
119119
# langsmith (needed for langchain_core) versions >= 0.3
120-
# (up to at least 0.3.2 as of 2025-01-29)
120+
# (up to at least 0.3.2 as of 2025-01-29)
121121
# cause an `argparse.ArgumentError` when running `pytest`.
122122
# https://github.com/posit-dev/py-shiny/issues/1829
123123
"langsmith<0.3",
@@ -158,7 +158,7 @@ ignore = ["E302", "E501", "F403", "F405", "W503", "E203", "E701", "E704"]
158158

159159
[tool.isort]
160160
profile = "black"
161-
skip = ["__init__.py", "typings/", "_dev/", ".venv", "venv", ".tox", "build"]
161+
skip = ["__init__.py", "typings/", "_dev/", ".venv", "venv", ".tox", "build", "_version.py"]
162162

163163
[tool.mypy]
164164
# The goal of our usage of mypy is to make to sure mypy can run, not that it catches any errors (we use pyright to find our errors).

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.

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

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

0 commit comments

Comments
 (0)