@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 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
- (_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "auto" });
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 effect:", {
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 = scrollToEnd || !userHasScrolled;
4589
- if (!idle && shouldAutoScroll && response && responseGotLonger) {
4590
- console.log("AIChatPanel - Calling scrollToBottom");
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, scrollToBottom, idle, userHasScrolled, scrollToEnd]);
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
- (_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "auto" });
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 effect:", {
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 = scrollToEnd || !userHasScrolled;
4556
- if (!idle && shouldAutoScroll && response && responseGotLonger) {
4557
- console.log("AIChatPanel - Calling scrollToBottom");
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, scrollToBottom, idle, userHasScrolled, scrollToEnd]);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hef2024/llmasaservice-ui",
3
- "version": "0.22.3",
3
+ "version": "0.22.5",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -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 effect:', {
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
- // CRITICAL: Only auto-scroll during active streaming when response grows
1846
- // This prevents scroll on layout changes (toast, context updates, etc.)
1847
- const shouldAutoScroll = scrollToEnd || !userHasScrolled;
1848
- if (!idle && shouldAutoScroll && response && responseGotLonger) {
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, scrollToBottom, idle, userHasScrolled, scrollToEnd]);
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;