@schlenkr/quassel 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat-scroll.d.ts +2 -1
- package/index.js +14 -16
- package/index.js.map +2 -2
- package/package.json +1 -1
package/chat-scroll.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ interface ScrollViewport {
|
|
|
3
3
|
readonly scrollHeight: number;
|
|
4
4
|
readonly clientHeight: number;
|
|
5
5
|
}
|
|
6
|
-
export declare
|
|
6
|
+
export declare const defaultJumpToEndThreshold = 120;
|
|
7
|
+
export declare function createChatScroll(onFollowChange?: (following: boolean) => void, getThreshold?: () => number): {
|
|
7
8
|
layout: (viewport: ScrollViewport, dragging?: boolean) => void;
|
|
8
9
|
pause(viewport: ScrollViewport): void;
|
|
9
10
|
scroll(viewport: ScrollViewport, dragging?: boolean): void;
|
package/index.js
CHANGED
|
@@ -170,9 +170,10 @@ import { createPortal } from "react-dom";
|
|
|
170
170
|
import { Dialog } from "@base-ui/react/dialog";
|
|
171
171
|
|
|
172
172
|
// packages/quassel/src/chat-scroll.ts
|
|
173
|
-
var
|
|
173
|
+
var defaultJumpToEndThreshold = 120;
|
|
174
174
|
function createChatScroll(onFollowChange = () => {
|
|
175
|
-
}) {
|
|
175
|
+
}, getThreshold = () => defaultJumpToEndThreshold) {
|
|
176
|
+
const atEnd = (viewport) => viewport.scrollHeight - viewport.clientHeight - viewport.scrollTop <= getThreshold();
|
|
176
177
|
let following = true;
|
|
177
178
|
let lastTop = 0;
|
|
178
179
|
let lastHeight = 0;
|
|
@@ -191,18 +192,18 @@ function createChatScroll(onFollowChange = () => {
|
|
|
191
192
|
const layout = (viewport, dragging = false) => {
|
|
192
193
|
if (viewport.clientHeight <= 0) return;
|
|
193
194
|
if (movedUp(viewport, dragging) && !atEnd(viewport)) follow(false);
|
|
195
|
+
if (atEnd(viewport)) follow(true);
|
|
194
196
|
if (following) viewport.scrollTop = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
|
|
195
|
-
else if (viewport.scrollHeight <= viewport.clientHeight) follow(true);
|
|
196
197
|
remember(viewport);
|
|
197
198
|
};
|
|
198
199
|
return {
|
|
199
200
|
layout,
|
|
200
201
|
pause(viewport) {
|
|
201
|
-
if (viewport.
|
|
202
|
+
if (viewport.clientHeight > 0) follow(atEnd(viewport));
|
|
202
203
|
},
|
|
203
204
|
scroll(viewport, dragging = false) {
|
|
204
205
|
if (viewport.clientHeight <= 0) return;
|
|
205
|
-
if (atEnd(viewport)
|
|
206
|
+
if (atEnd(viewport)) follow(true);
|
|
206
207
|
else if (movedUp(viewport, dragging) && !atEnd(viewport)) follow(false);
|
|
207
208
|
remember(viewport);
|
|
208
209
|
},
|
|
@@ -1223,7 +1224,7 @@ function ChatMessages({
|
|
|
1223
1224
|
scrollerRef,
|
|
1224
1225
|
maxWidth,
|
|
1225
1226
|
horizontalPadding,
|
|
1226
|
-
jumpToEndThreshold =
|
|
1227
|
+
jumpToEndThreshold = defaultJumpToEndThreshold,
|
|
1227
1228
|
appearance,
|
|
1228
1229
|
timestampOptions,
|
|
1229
1230
|
codeBlockOptions,
|
|
@@ -1253,7 +1254,11 @@ function ChatMessages({
|
|
|
1253
1254
|
const scrollbarDragging = useRef3(false);
|
|
1254
1255
|
const touchY = useRef3(void 0);
|
|
1255
1256
|
const [showJumpToEnd, setShowJumpToEnd] = useState4(false);
|
|
1256
|
-
const
|
|
1257
|
+
const endThreshold = useRef3(jumpToEndThreshold);
|
|
1258
|
+
useLayoutEffect(() => {
|
|
1259
|
+
endThreshold.current = jumpToEndThreshold;
|
|
1260
|
+
}, [jumpToEndThreshold]);
|
|
1261
|
+
const [scroll] = useState4(() => createChatScroll((following) => setShowJumpToEnd(!following), () => endThreshold.current));
|
|
1257
1262
|
const sendScope = useContext3(ChatSendContext);
|
|
1258
1263
|
const dock = useContext3(ChatActionDock);
|
|
1259
1264
|
const [now, setNow] = useState4(() => Date.now());
|
|
@@ -1275,15 +1280,11 @@ function ChatMessages({
|
|
|
1275
1280
|
}
|
|
1276
1281
|
due.filter((message) => selected.includes(message)).map((message) => announce2 ? announce2({ kind: message.role === "action" ? "action" : "reply", message }) : markdownPlainText(message.text)).forEach((text) => text && announce(text));
|
|
1277
1282
|
}, [messages, selected, running2, announce2]);
|
|
1278
|
-
const updateJumpVisibility = useCallback2((viewport) => {
|
|
1279
|
-
if (viewport.clientHeight > 0) setShowJumpToEnd(viewport.scrollHeight - viewport.clientHeight - viewport.scrollTop > jumpToEndThreshold);
|
|
1280
|
-
}, [jumpToEndThreshold]);
|
|
1281
1283
|
useLayoutEffect(() => sendScope?.subscribe(() => {
|
|
1282
1284
|
const viewport = scrollArea.current;
|
|
1283
1285
|
if (!viewport) return;
|
|
1284
1286
|
scroll.jump(viewport);
|
|
1285
|
-
|
|
1286
|
-
}), [sendScope, scroll, updateJumpVisibility]);
|
|
1287
|
+
}), [sendScope, scroll]);
|
|
1287
1288
|
const pauseUp = (viewport, target) => {
|
|
1288
1289
|
let element = target instanceof Element ? target : null;
|
|
1289
1290
|
while (element && element !== viewport) {
|
|
@@ -1296,9 +1297,8 @@ function ChatMessages({
|
|
|
1296
1297
|
const area = scrollArea.current;
|
|
1297
1298
|
if (area) {
|
|
1298
1299
|
scroll.scroll(area, scrollbarDragging.current);
|
|
1299
|
-
updateJumpVisibility(area);
|
|
1300
1300
|
}
|
|
1301
|
-
}, [scroll
|
|
1301
|
+
}, [scroll]);
|
|
1302
1302
|
useEffect3(() => {
|
|
1303
1303
|
const finishDrag = () => {
|
|
1304
1304
|
if (scrollbarDragging.current && scrollArea.current) scroll.scroll(scrollArea.current, true);
|
|
@@ -1316,7 +1316,6 @@ function ChatMessages({
|
|
|
1316
1316
|
if (!area) return;
|
|
1317
1317
|
const align = () => {
|
|
1318
1318
|
scroll.layout(area, scrollbarDragging.current);
|
|
1319
|
-
updateJumpVisibility(area);
|
|
1320
1319
|
};
|
|
1321
1320
|
align();
|
|
1322
1321
|
const observer = new ResizeObserver(align);
|
|
@@ -1520,7 +1519,6 @@ function ChatMessages({
|
|
|
1520
1519
|
showJumpToEnd && /* @__PURE__ */ jsx13("div", { className: "qsl:pointer-events-none qsl:absolute qsl:inset-x-0 qsl:bottom-[calc(var(--qsl-composer-height,0px)_+_12px)] qsl:z-10 qsl:flex qsl:justify-center", children: /* @__PURE__ */ jsx13(Button2, { "aria-label": allTexts.jumpToEnd, className: "qsl:pointer-events-auto qsl:rounded-full qsl:border qsl:border-primary-foreground/20 qsl:shadow-md", size: "icon", title: allTexts.jumpToEnd, variant: "default", onClick: () => {
|
|
1521
1520
|
if (scrollArea.current) {
|
|
1522
1521
|
scroll.jump(scrollArea.current);
|
|
1523
|
-
updateJumpVisibility(scrollArea.current);
|
|
1524
1522
|
}
|
|
1525
1523
|
}, children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) }) }),
|
|
1526
1524
|
dock && openActions.length > 0 && createPortal(
|