overflow-anchor to hold view to bottom of scrollable action output (#19452)

This commit is contained in:
Phil Renaud
2023-12-13 15:19:22 -05:00
committed by GitHub
parent 9b2e8ae20f
commit 49b4996d46
4 changed files with 53 additions and 3 deletions

3
.changelog/19452.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
ui: when an Action has long output, anchor to the latest messages
```

View File

@@ -71,7 +71,12 @@
<code><pre>Error: {{this.instance.error}}</pre></code>
{{/if}}
{{#if this.instance.messages.length}}
<code><pre>{{this.instance.messages}}</pre></code>
<code tabindex="0">
<pre {{did-update this.anchorToBottom this.instance.messages}}>
{{this.instance.messages}}
</pre>
<div class="anchor" />
</code>
{{else}}
{{#if (eq this.instance.state "complete")}}
<p class="no-messages">Action completed with no output</p>

View File

@@ -48,4 +48,30 @@ export default class ActionCardComponent extends Component {
// Either the passed instance, or the peer-selected instance
return this.selectedPeer || this.args.instance;
}
@tracked hasBeenAnchored = false;
/**
* Runs from the action-card template whenever instance.messages updates,
* and serves to keep the user's view anchored to the bottom of the messages.
* This uses a hidden element and the overflow-anchor css attribute, which
* keeps the element visible within the scrollable <code> block parent.
* A trick here is that, if the user scrolls up from the bottom of the block,
* we don't want to force them down to the bottom again on update, but we do
* want to keep them there by default (so they have the latest output).
* The hasBeenAnchored flag is used to track this state, and we do a little
* trick when the messages get long enough to cause a scroll to start the
* anchoring process here.
*
* @param {HTMLElement} element
*/
@action anchorToBottom(element) {
if (this.hasBeenAnchored) return;
const parentHeight = element.parentElement.clientHeight;
const elementHeight = element.clientHeight;
if (elementHeight > parentHeight) {
this.hasBeenAnchored = true;
element.parentElement.scroll(0, elementHeight);
}
}
}

View File

@@ -117,14 +117,30 @@
}
.messages {
width: 100%;
overflow: hidden;
code > pre {
height: 200px;
code {
background-color: #0a0a0a;
color: whitesmoke;
display: block;
overflow: auto;
height: 200px;
border-radius: 6px;
resize: vertical;
pre {
background-color: transparent;
color: unset;
overflow-anchor: none;
min-height: 100%;
white-space: pre-wrap;
}
.anchor {
overflow-anchor: auto;
height: 1px;
margin-top: -1px;
visibility: hidden;
}
}
}