Commit
•
77c7055
1
Parent(s):
5be0e20
Fix scroll to bottom (#78)
Browse files* fix snap scroll to bottom not updating properly to bottom when switching conversation
* scroll to bottom when a user sends a new message ( fixes #75)
* update comment to be detailing the scroll offset
Co-authored-by: Eliott C. <[email protected]>
* use tick() instead of afterUpdate
---------
Co-authored-by: Eliott C. <[email protected]>
src/lib/actions/snapScrollToBottom.ts
CHANGED
@@ -1,6 +1,9 @@
|
|
1 |
import { navigating } from "$app/stores";
|
|
|
2 |
import { get } from "svelte/store";
|
3 |
|
|
|
|
|
4 |
/**
|
5 |
* @param node element to snap scroll to bottom
|
6 |
* @param dependency pass in a dependency to update scroll on changes.
|
@@ -15,24 +18,25 @@ export const snapScrollToBottom = (node: HTMLElement, dependency: any) => {
|
|
15 |
isDetached = true;
|
16 |
}
|
17 |
|
18 |
-
// if user scrolled back to bottom, we reattach
|
19 |
-
if (node.scrollTop
|
20 |
isDetached = false;
|
21 |
}
|
22 |
|
23 |
prevScrollValue = node.scrollTop;
|
24 |
};
|
25 |
|
26 |
-
const updateScroll = (_options: { force?: boolean } = {}) => {
|
27 |
const defaultOptions = { force: false };
|
28 |
const options = { ...defaultOptions, ..._options };
|
29 |
const { force } = options;
|
30 |
|
31 |
if (!force && isDetached && !get(navigating)) return;
|
32 |
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
36 |
};
|
37 |
|
38 |
node.addEventListener("scroll", handleScroll);
|
|
|
1 |
import { navigating } from "$app/stores";
|
2 |
+
import { tick } from "svelte";
|
3 |
import { get } from "svelte/store";
|
4 |
|
5 |
+
const detachedOffset = 10;
|
6 |
+
|
7 |
/**
|
8 |
* @param node element to snap scroll to bottom
|
9 |
* @param dependency pass in a dependency to update scroll on changes.
|
|
|
18 |
isDetached = true;
|
19 |
}
|
20 |
|
21 |
+
// if user scrolled back to within 10px of bottom, we reattach
|
22 |
+
if (node.scrollTop - (node.scrollHeight - node.clientHeight) >= -detachedOffset) {
|
23 |
isDetached = false;
|
24 |
}
|
25 |
|
26 |
prevScrollValue = node.scrollTop;
|
27 |
};
|
28 |
|
29 |
+
const updateScroll = async (_options: { force?: boolean } = {}) => {
|
30 |
const defaultOptions = { force: false };
|
31 |
const options = { ...defaultOptions, ..._options };
|
32 |
const { force } = options;
|
33 |
|
34 |
if (!force && isDetached && !get(navigating)) return;
|
35 |
|
36 |
+
// wait for next tick to ensure that the DOM is updated
|
37 |
+
await tick();
|
38 |
+
|
39 |
+
node.scrollTo({ top: node.scrollHeight });
|
40 |
};
|
41 |
|
42 |
node.addEventListener("scroll", handleScroll);
|
src/lib/components/chat/ChatMessages.svelte
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
import { snapScrollToBottom } from "$lib/actions/snapScrollToBottom";
|
4 |
import ScrollToBottomBtn from "$lib/components/ScrollToBottomBtn.svelte";
|
|
|
|
|
5 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
6 |
import ChatMessage from "./ChatMessage.svelte";
|
7 |
|
@@ -10,6 +12,16 @@
|
|
10 |
export let pending: boolean;
|
11 |
|
12 |
let chatContainer: HTMLElement;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</script>
|
14 |
|
15 |
<div class="overflow-y-auto h-full" use:snapScrollToBottom={messages} bind:this={chatContainer}>
|
|
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
import { snapScrollToBottom } from "$lib/actions/snapScrollToBottom";
|
4 |
import ScrollToBottomBtn from "$lib/components/ScrollToBottomBtn.svelte";
|
5 |
+
import { tick } from "svelte";
|
6 |
+
|
7 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
8 |
import ChatMessage from "./ChatMessage.svelte";
|
9 |
|
|
|
12 |
export let pending: boolean;
|
13 |
|
14 |
let chatContainer: HTMLElement;
|
15 |
+
|
16 |
+
async function scrollToBottom() {
|
17 |
+
await tick();
|
18 |
+
chatContainer.scrollTop = chatContainer.scrollHeight;
|
19 |
+
}
|
20 |
+
|
21 |
+
// If last message is from user, scroll to bottom
|
22 |
+
$: if (messages.at(-1)?.from === "user") {
|
23 |
+
scrollToBottom();
|
24 |
+
}
|
25 |
</script>
|
26 |
|
27 |
<div class="overflow-y-auto h-full" use:snapScrollToBottom={messages} bind:this={chatContainer}>
|