@hef2024/llmasaservice-ui 0.22.3 → 0.22.5
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/dist/index.js +43 -12
- package/dist/index.mjs +43 -12
- package/package.json +1 -1
- package/src/AIChatPanel.tsx +53 -15
package/dist/index.js
CHANGED
|
@@ -3895,6 +3895,8 @@ var AIChatPanel = ({
|
|
|
3895
3895
|
const scrollRAFRef = (0, import_react12.useRef)(null);
|
|
3896
3896
|
const lastScrollTimeRef = (0, import_react12.useRef)(0);
|
|
3897
3897
|
const prevResponseLengthRef = (0, import_react12.useRef)(0);
|
|
3898
|
+
const scrollToEndRef = (0, import_react12.useRef)(scrollToEnd || false);
|
|
3899
|
+
const userHasScrolledRef = (0, import_react12.useRef)(userHasScrolled);
|
|
3898
3900
|
const prevIdleRef = (0, import_react12.useRef)(true);
|
|
3899
3901
|
const hasNotifiedCompletionRef = (0, import_react12.useRef)(true);
|
|
3900
3902
|
const latestHistoryRef = (0, import_react12.useRef)(initialHistory);
|
|
@@ -4336,7 +4338,13 @@ var AIChatPanel = ({
|
|
|
4336
4338
|
}
|
|
4337
4339
|
}), [thumbsDownClick, interactionClicked]);
|
|
4338
4340
|
const scrollToBottom = (0, import_react12.useCallback)((force = false) => {
|
|
4339
|
-
var _a2;
|
|
4341
|
+
var _a2, _b;
|
|
4342
|
+
console.log("\u{1F535} scrollToBottom called", {
|
|
4343
|
+
force,
|
|
4344
|
+
idle: idleRef.current,
|
|
4345
|
+
calledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4346
|
+
stackTrace: (_a2 = new Error().stack) == null ? void 0 : _a2.split("\n").slice(2, 4).join("\n")
|
|
4347
|
+
});
|
|
4340
4348
|
if (scrollRAFRef.current) {
|
|
4341
4349
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
4342
4350
|
}
|
|
@@ -4347,10 +4355,19 @@ var AIChatPanel = ({
|
|
|
4347
4355
|
const scrollHeight = scrollElement.scrollHeight;
|
|
4348
4356
|
const clientHeight = scrollElement.clientHeight;
|
|
4349
4357
|
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
4358
|
+
console.log("\u{1F535} scrollToBottom: checking position", {
|
|
4359
|
+
scrollTop,
|
|
4360
|
+
scrollHeight,
|
|
4361
|
+
clientHeight,
|
|
4362
|
+
distanceFromBottom: scrollHeight - scrollTop - clientHeight,
|
|
4363
|
+
isNearBottom
|
|
4364
|
+
});
|
|
4350
4365
|
if (!isNearBottom) {
|
|
4366
|
+
console.log("\u{1F535} scrollToBottom: CANCELLED (not near bottom)");
|
|
4351
4367
|
return;
|
|
4352
4368
|
}
|
|
4353
4369
|
}
|
|
4370
|
+
console.log("\u{1F535} scrollToBottom: EXECUTING SCROLL", { force });
|
|
4354
4371
|
const now = Date.now();
|
|
4355
4372
|
if (now - lastScrollTimeRef.current < 100) {
|
|
4356
4373
|
scrollRAFRef.current = requestAnimationFrame(() => {
|
|
@@ -4360,7 +4377,7 @@ var AIChatPanel = ({
|
|
|
4360
4377
|
});
|
|
4361
4378
|
return;
|
|
4362
4379
|
}
|
|
4363
|
-
(
|
|
4380
|
+
(_b = bottomRef.current) == null ? void 0 : _b.scrollIntoView({ behavior: "auto" });
|
|
4364
4381
|
lastScrollTimeRef.current = now;
|
|
4365
4382
|
}, []);
|
|
4366
4383
|
const continueChat = (0, import_react12.useCallback)((promptText) => {
|
|
@@ -4574,27 +4591,41 @@ var AIChatPanel = ({
|
|
|
4574
4591
|
}
|
|
4575
4592
|
}, [idle]);
|
|
4576
4593
|
(0, import_react12.useEffect)(() => {
|
|
4594
|
+
scrollToEndRef.current = scrollToEnd || false;
|
|
4595
|
+
}, [scrollToEnd]);
|
|
4596
|
+
(0, import_react12.useEffect)(() => {
|
|
4597
|
+
userHasScrolledRef.current = userHasScrolled;
|
|
4598
|
+
}, [userHasScrolled]);
|
|
4599
|
+
(0, import_react12.useEffect)(() => {
|
|
4600
|
+
console.log("AIChatPanel - Auto-scroll effect triggered", {
|
|
4601
|
+
idle,
|
|
4602
|
+
responseLength: response.length,
|
|
4603
|
+
effectRanAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4604
|
+
});
|
|
4605
|
+
if (idle) {
|
|
4606
|
+
console.log("AIChatPanel - Auto-scroll effect: SKIPPED (idle=true)");
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4577
4609
|
const currentResponseLength = response.length;
|
|
4578
4610
|
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
4579
|
-
console.log("AIChatPanel - Auto-scroll
|
|
4580
|
-
idle,
|
|
4611
|
+
console.log("AIChatPanel - Auto-scroll checks:", {
|
|
4581
4612
|
currentResponseLength,
|
|
4582
4613
|
prevLength: prevResponseLengthRef.current,
|
|
4583
4614
|
responseGotLonger,
|
|
4584
|
-
userHasScrolled,
|
|
4585
|
-
scrollToEnd
|
|
4615
|
+
userHasScrolled: userHasScrolledRef.current,
|
|
4616
|
+
scrollToEnd: scrollToEndRef.current
|
|
4586
4617
|
});
|
|
4587
4618
|
prevResponseLengthRef.current = currentResponseLength;
|
|
4588
|
-
const shouldAutoScroll =
|
|
4589
|
-
if (
|
|
4590
|
-
console.log("AIChatPanel -
|
|
4619
|
+
const shouldAutoScroll = scrollToEndRef.current || !userHasScrolledRef.current;
|
|
4620
|
+
if (shouldAutoScroll && response && responseGotLonger) {
|
|
4621
|
+
console.log("AIChatPanel - \u2705 SCROLLING TO BOTTOM");
|
|
4591
4622
|
scrollToBottom(false);
|
|
4623
|
+
} else {
|
|
4624
|
+
console.log("AIChatPanel - \u274C NOT scrolling (conditions not met)");
|
|
4592
4625
|
}
|
|
4593
|
-
}, [response,
|
|
4626
|
+
}, [response, idle]);
|
|
4594
4627
|
const idleRef = (0, import_react12.useRef)(idle);
|
|
4595
4628
|
idleRef.current = idle;
|
|
4596
|
-
const userHasScrolledRef = (0, import_react12.useRef)(userHasScrolled);
|
|
4597
|
-
userHasScrolledRef.current = userHasScrolled;
|
|
4598
4629
|
(0, import_react12.useEffect)(() => {
|
|
4599
4630
|
const scrollArea = responseAreaRef.current;
|
|
4600
4631
|
if (!scrollArea) return;
|
package/dist/index.mjs
CHANGED
|
@@ -3862,6 +3862,8 @@ var AIChatPanel = ({
|
|
|
3862
3862
|
const scrollRAFRef = useRef5(null);
|
|
3863
3863
|
const lastScrollTimeRef = useRef5(0);
|
|
3864
3864
|
const prevResponseLengthRef = useRef5(0);
|
|
3865
|
+
const scrollToEndRef = useRef5(scrollToEnd || false);
|
|
3866
|
+
const userHasScrolledRef = useRef5(userHasScrolled);
|
|
3865
3867
|
const prevIdleRef = useRef5(true);
|
|
3866
3868
|
const hasNotifiedCompletionRef = useRef5(true);
|
|
3867
3869
|
const latestHistoryRef = useRef5(initialHistory);
|
|
@@ -4303,7 +4305,13 @@ var AIChatPanel = ({
|
|
|
4303
4305
|
}
|
|
4304
4306
|
}), [thumbsDownClick, interactionClicked]);
|
|
4305
4307
|
const scrollToBottom = useCallback2((force = false) => {
|
|
4306
|
-
var _a2;
|
|
4308
|
+
var _a2, _b;
|
|
4309
|
+
console.log("\u{1F535} scrollToBottom called", {
|
|
4310
|
+
force,
|
|
4311
|
+
idle: idleRef.current,
|
|
4312
|
+
calledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4313
|
+
stackTrace: (_a2 = new Error().stack) == null ? void 0 : _a2.split("\n").slice(2, 4).join("\n")
|
|
4314
|
+
});
|
|
4307
4315
|
if (scrollRAFRef.current) {
|
|
4308
4316
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
4309
4317
|
}
|
|
@@ -4314,10 +4322,19 @@ var AIChatPanel = ({
|
|
|
4314
4322
|
const scrollHeight = scrollElement.scrollHeight;
|
|
4315
4323
|
const clientHeight = scrollElement.clientHeight;
|
|
4316
4324
|
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
4325
|
+
console.log("\u{1F535} scrollToBottom: checking position", {
|
|
4326
|
+
scrollTop,
|
|
4327
|
+
scrollHeight,
|
|
4328
|
+
clientHeight,
|
|
4329
|
+
distanceFromBottom: scrollHeight - scrollTop - clientHeight,
|
|
4330
|
+
isNearBottom
|
|
4331
|
+
});
|
|
4317
4332
|
if (!isNearBottom) {
|
|
4333
|
+
console.log("\u{1F535} scrollToBottom: CANCELLED (not near bottom)");
|
|
4318
4334
|
return;
|
|
4319
4335
|
}
|
|
4320
4336
|
}
|
|
4337
|
+
console.log("\u{1F535} scrollToBottom: EXECUTING SCROLL", { force });
|
|
4321
4338
|
const now = Date.now();
|
|
4322
4339
|
if (now - lastScrollTimeRef.current < 100) {
|
|
4323
4340
|
scrollRAFRef.current = requestAnimationFrame(() => {
|
|
@@ -4327,7 +4344,7 @@ var AIChatPanel = ({
|
|
|
4327
4344
|
});
|
|
4328
4345
|
return;
|
|
4329
4346
|
}
|
|
4330
|
-
(
|
|
4347
|
+
(_b = bottomRef.current) == null ? void 0 : _b.scrollIntoView({ behavior: "auto" });
|
|
4331
4348
|
lastScrollTimeRef.current = now;
|
|
4332
4349
|
}, []);
|
|
4333
4350
|
const continueChat = useCallback2((promptText) => {
|
|
@@ -4541,27 +4558,41 @@ var AIChatPanel = ({
|
|
|
4541
4558
|
}
|
|
4542
4559
|
}, [idle]);
|
|
4543
4560
|
useEffect7(() => {
|
|
4561
|
+
scrollToEndRef.current = scrollToEnd || false;
|
|
4562
|
+
}, [scrollToEnd]);
|
|
4563
|
+
useEffect7(() => {
|
|
4564
|
+
userHasScrolledRef.current = userHasScrolled;
|
|
4565
|
+
}, [userHasScrolled]);
|
|
4566
|
+
useEffect7(() => {
|
|
4567
|
+
console.log("AIChatPanel - Auto-scroll effect triggered", {
|
|
4568
|
+
idle,
|
|
4569
|
+
responseLength: response.length,
|
|
4570
|
+
effectRanAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4571
|
+
});
|
|
4572
|
+
if (idle) {
|
|
4573
|
+
console.log("AIChatPanel - Auto-scroll effect: SKIPPED (idle=true)");
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4544
4576
|
const currentResponseLength = response.length;
|
|
4545
4577
|
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
4546
|
-
console.log("AIChatPanel - Auto-scroll
|
|
4547
|
-
idle,
|
|
4578
|
+
console.log("AIChatPanel - Auto-scroll checks:", {
|
|
4548
4579
|
currentResponseLength,
|
|
4549
4580
|
prevLength: prevResponseLengthRef.current,
|
|
4550
4581
|
responseGotLonger,
|
|
4551
|
-
userHasScrolled,
|
|
4552
|
-
scrollToEnd
|
|
4582
|
+
userHasScrolled: userHasScrolledRef.current,
|
|
4583
|
+
scrollToEnd: scrollToEndRef.current
|
|
4553
4584
|
});
|
|
4554
4585
|
prevResponseLengthRef.current = currentResponseLength;
|
|
4555
|
-
const shouldAutoScroll =
|
|
4556
|
-
if (
|
|
4557
|
-
console.log("AIChatPanel -
|
|
4586
|
+
const shouldAutoScroll = scrollToEndRef.current || !userHasScrolledRef.current;
|
|
4587
|
+
if (shouldAutoScroll && response && responseGotLonger) {
|
|
4588
|
+
console.log("AIChatPanel - \u2705 SCROLLING TO BOTTOM");
|
|
4558
4589
|
scrollToBottom(false);
|
|
4590
|
+
} else {
|
|
4591
|
+
console.log("AIChatPanel - \u274C NOT scrolling (conditions not met)");
|
|
4559
4592
|
}
|
|
4560
|
-
}, [response,
|
|
4593
|
+
}, [response, idle]);
|
|
4561
4594
|
const idleRef = useRef5(idle);
|
|
4562
4595
|
idleRef.current = idle;
|
|
4563
|
-
const userHasScrolledRef = useRef5(userHasScrolled);
|
|
4564
|
-
userHasScrolledRef.current = userHasScrolled;
|
|
4565
4596
|
useEffect7(() => {
|
|
4566
4597
|
const scrollArea = responseAreaRef.current;
|
|
4567
4598
|
if (!scrollArea) return;
|
package/package.json
CHANGED
package/src/AIChatPanel.tsx
CHANGED
|
@@ -847,6 +847,8 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
847
847
|
const scrollRAFRef = useRef<number | null>(null);
|
|
848
848
|
const lastScrollTimeRef = useRef<number>(0);
|
|
849
849
|
const prevResponseLengthRef = useRef<number>(0);
|
|
850
|
+
const scrollToEndRef = useRef<boolean>(scrollToEnd || false);
|
|
851
|
+
const userHasScrolledRef = useRef<boolean>(userHasScrolled);
|
|
850
852
|
|
|
851
853
|
// === NEW: Clean history management refs ===
|
|
852
854
|
// Track previous idle state to detect transitions (false→true = completion)
|
|
@@ -1472,6 +1474,13 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1472
1474
|
|
|
1473
1475
|
// Scroll to bottom - throttled using RAF to prevent layout thrashing
|
|
1474
1476
|
const scrollToBottom = useCallback((force: boolean = false) => {
|
|
1477
|
+
console.log('🔵 scrollToBottom called', {
|
|
1478
|
+
force,
|
|
1479
|
+
idle: idleRef.current,
|
|
1480
|
+
calledAt: new Date().toISOString(),
|
|
1481
|
+
stackTrace: new Error().stack?.split('\n').slice(2, 4).join('\n')
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1475
1484
|
// Cancel any pending scroll
|
|
1476
1485
|
if (scrollRAFRef.current) {
|
|
1477
1486
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
@@ -1487,12 +1496,23 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1487
1496
|
const clientHeight = scrollElement.clientHeight;
|
|
1488
1497
|
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
1489
1498
|
|
|
1499
|
+
console.log('🔵 scrollToBottom: checking position', {
|
|
1500
|
+
scrollTop,
|
|
1501
|
+
scrollHeight,
|
|
1502
|
+
clientHeight,
|
|
1503
|
+
distanceFromBottom: scrollHeight - scrollTop - clientHeight,
|
|
1504
|
+
isNearBottom
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1490
1507
|
// If user is not near bottom, don't scroll (prevents scroll on layout changes like toast)
|
|
1491
1508
|
if (!isNearBottom) {
|
|
1509
|
+
console.log('🔵 scrollToBottom: CANCELLED (not near bottom)');
|
|
1492
1510
|
return;
|
|
1493
1511
|
}
|
|
1494
1512
|
}
|
|
1495
1513
|
|
|
1514
|
+
console.log('🔵 scrollToBottom: EXECUTING SCROLL', { force });
|
|
1515
|
+
|
|
1496
1516
|
// Throttle to max once per 100ms to prevent performance issues during streaming
|
|
1497
1517
|
const now = Date.now();
|
|
1498
1518
|
if (now - lastScrollTimeRef.current < 100) {
|
|
@@ -1821,45 +1841,63 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1821
1841
|
}
|
|
1822
1842
|
}, [idle]); // ONLY depends on idle - no history, no callbacks in deps
|
|
1823
1843
|
|
|
1844
|
+
// Keep refs in sync
|
|
1845
|
+
useEffect(() => {
|
|
1846
|
+
scrollToEndRef.current = scrollToEnd || false;
|
|
1847
|
+
}, [scrollToEnd]);
|
|
1848
|
+
|
|
1849
|
+
useEffect(() => {
|
|
1850
|
+
userHasScrolledRef.current = userHasScrolled;
|
|
1851
|
+
}, [userHasScrolled]);
|
|
1852
|
+
|
|
1824
1853
|
// Auto-scroll to bottom - only while streaming and user hasn't manually scrolled
|
|
1854
|
+
// CRITICAL: Only depends on response and idle to avoid re-running on layout changes
|
|
1825
1855
|
useEffect(() => {
|
|
1856
|
+
console.log('AIChatPanel - Auto-scroll effect triggered', {
|
|
1857
|
+
idle,
|
|
1858
|
+
responseLength: response.length,
|
|
1859
|
+
effectRanAt: new Date().toISOString(),
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
// CRITICAL: Skip entirely if idle - no scrolling when not streaming
|
|
1863
|
+
if (idle) {
|
|
1864
|
+
console.log('AIChatPanel - Auto-scroll effect: SKIPPED (idle=true)');
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1826
1868
|
// Only auto-scroll if:
|
|
1827
|
-
// 1. We're actively streaming (!idle)
|
|
1869
|
+
// 1. We're actively streaming (!idle) - checked above
|
|
1828
1870
|
// 2. User hasn't manually scrolled up during this response (or scrollToEnd prop is true)
|
|
1829
1871
|
// 3. We have content to show (response exists)
|
|
1830
1872
|
// 4. The response actually got longer (not just a re-render from layout change)
|
|
1831
1873
|
const currentResponseLength = response.length;
|
|
1832
1874
|
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
1833
1875
|
|
|
1834
|
-
console.log('AIChatPanel - Auto-scroll
|
|
1835
|
-
idle,
|
|
1876
|
+
console.log('AIChatPanel - Auto-scroll checks:', {
|
|
1836
1877
|
currentResponseLength,
|
|
1837
1878
|
prevLength: prevResponseLengthRef.current,
|
|
1838
1879
|
responseGotLonger,
|
|
1839
|
-
userHasScrolled,
|
|
1840
|
-
scrollToEnd,
|
|
1880
|
+
userHasScrolled: userHasScrolledRef.current,
|
|
1881
|
+
scrollToEnd: scrollToEndRef.current,
|
|
1841
1882
|
});
|
|
1842
1883
|
|
|
1843
1884
|
prevResponseLengthRef.current = currentResponseLength;
|
|
1844
1885
|
|
|
1845
|
-
//
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
console.log('AIChatPanel - Calling scrollToBottom');
|
|
1886
|
+
// Only scroll if response actually grew - use refs to avoid unnecessary effect runs
|
|
1887
|
+
const shouldAutoScroll = scrollToEndRef.current || !userHasScrolledRef.current;
|
|
1888
|
+
if (shouldAutoScroll && response && responseGotLonger) {
|
|
1889
|
+
console.log('AIChatPanel - ✅ SCROLLING TO BOTTOM');
|
|
1850
1890
|
// Use non-forced scroll - will only scroll if near bottom
|
|
1851
1891
|
scrollToBottom(false);
|
|
1892
|
+
} else {
|
|
1893
|
+
console.log('AIChatPanel - ❌ NOT scrolling (conditions not met)');
|
|
1852
1894
|
}
|
|
1853
|
-
}, [response,
|
|
1895
|
+
}, [response, idle]); // ONLY response and idle - no other dependencies!
|
|
1854
1896
|
|
|
1855
1897
|
// Ref to track idle state for scroll handler (avoids stale closure)
|
|
1856
1898
|
const idleRef = useRef(idle);
|
|
1857
1899
|
idleRef.current = idle;
|
|
1858
1900
|
|
|
1859
|
-
// Ref to track userHasScrolled to avoid redundant state updates
|
|
1860
|
-
const userHasScrolledRef = useRef(userHasScrolled);
|
|
1861
|
-
userHasScrolledRef.current = userHasScrolled;
|
|
1862
|
-
|
|
1863
1901
|
// Detect user scroll to disable auto-scroll
|
|
1864
1902
|
useEffect(() => {
|
|
1865
1903
|
const scrollArea = responseAreaRef.current;
|