@@ -46,6 +46,7 @@ const CHAT_MESSAGE_TAG = "shiny-chat-message";
4646const CHAT_USER_MESSAGE_TAG = "shiny-user-message" ;
4747const CHAT_MESSAGES_TAG = "shiny-chat-messages" ;
4848const CHAT_INPUT_TAG = "shiny-chat-input" ;
49+ const CHAT_INPUT_SENTINEL_TAG = "shiny-chat-input-sentinel" ;
4950const CHAT_CONTAINER_TAG = "shiny-chat-container" ;
5051
5152const ICONS = {
@@ -262,6 +263,8 @@ class ChatInput extends LightElement {
262263}
263264
264265class ChatContainer extends LightElement {
266+ inputSentinel ?: HTMLElement ;
267+ inputSentinelObserver ?: IntersectionObserver ;
265268
266269 private get input ( ) : ChatInput {
267270 return this . querySelector ( CHAT_INPUT_TAG ) as ChatInput ;
@@ -280,6 +283,34 @@ class ChatContainer extends LightElement {
280283 return html `` ;
281284 }
282285
286+ connectedCallback ( ) : void {
287+ super . connectedCallback ( ) ;
288+
289+ // We use a sentinel element that we place just above the shiny-chat-input. When it
290+ // moves off-screen we know that the text area input is now floating, add shadow.
291+ let sentinel = this . querySelector < HTMLElement > ( CHAT_INPUT_SENTINEL_TAG ) ;
292+ if ( ! sentinel ) {
293+ sentinel = createElement ( CHAT_INPUT_SENTINEL_TAG , { } ) as HTMLElement ;
294+ this . input . insertAdjacentElement ( "beforebegin" , sentinel ) ;
295+ }
296+
297+ this . inputSentinel = sentinel ;
298+ this . inputSentinelObserver = new IntersectionObserver (
299+ ( entries ) => {
300+ const inputTextarea = this . input . querySelector ( "textarea" ) ;
301+ if ( ! inputTextarea ) return ;
302+ const addShadow = entries [ 0 ] ?. intersectionRatio === 0 ;
303+ inputTextarea . classList . toggle ( "shadow" , addShadow ) ;
304+ } ,
305+ {
306+ threshold : [ 0 , 1 ] ,
307+ rootMargin : "0px" ,
308+ }
309+ ) ;
310+
311+ this . inputSentinelObserver . observe ( this . inputSentinel ) ;
312+ }
313+
283314 firstUpdated ( ) : void {
284315 // Don't attach event listeners until child elements are rendered
285316 if ( ! this . messages ) return ;
@@ -306,6 +337,9 @@ class ChatContainer extends LightElement {
306337 disconnectedCallback ( ) : void {
307338 super . disconnectedCallback ( ) ;
308339
340+ this . inputSentinelObserver ?. disconnect ( ) ;
341+ this . inputSentinel ?. remove ( ) ;
342+
309343 this . removeEventListener ( "shiny-chat-input-sent" , this . #onInputSent) ;
310344 this . removeEventListener ( "shiny-chat-append-message" , this . #onAppend) ;
311345 this . removeEventListener (
0 commit comments