@fusion.dev/helix-headless 0.212.1 → 0.212.2
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/custom-elements.json +1 -1
- package/dist/chat/root/chat-root.d.ts +38 -2
- package/dist/chat/root/chat-root.js +42 -3
- package/lint.json +1 -1
- package/package.json +5 -5
|
@@ -346,6 +346,8 @@ export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
|
346
346
|
private grower;
|
|
347
347
|
/** What `grower` is watching, so a render that changed nothing re-observes nothing. */
|
|
348
348
|
private watched;
|
|
349
|
+
/** The frame `watchSizes` will observe in, while one is booked. */
|
|
350
|
+
private watchFrame;
|
|
349
351
|
/** The scroll offset this element last set, which the reader has not moved from. */
|
|
350
352
|
private stuckAt;
|
|
351
353
|
/** The turn at the top of the reader's view, and how far below the top it sat. */
|
|
@@ -424,7 +426,15 @@ export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
|
424
426
|
* a reader asking to go to the bottom means.
|
|
425
427
|
*/
|
|
426
428
|
resume(): void;
|
|
427
|
-
/**
|
|
429
|
+
/**
|
|
430
|
+
* Scrolls to the bottom, and remembers where that was.
|
|
431
|
+
*
|
|
432
|
+
* **At once, whatever `scroll-behavior` the page gives the log.** Pinned,
|
|
433
|
+
* this runs on every update, every token of a streaming turn included, and a
|
|
434
|
+
* smooth scroll sent again each time never arrives: in WebKit, a log that had
|
|
435
|
+
* streamed for a second under `scroll-behavior: smooth` rested 6 pixels short
|
|
436
|
+
* of the bottom, and `stuckAt` held where each scroll began.
|
|
437
|
+
*/
|
|
428
438
|
private stick;
|
|
429
439
|
/**
|
|
430
440
|
* Asks to pin or unpin, and reports whether the request stood.
|
|
@@ -496,8 +506,34 @@ export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
|
496
506
|
* in a conversation of several knows who spoke.
|
|
497
507
|
*/
|
|
498
508
|
private phrase;
|
|
499
|
-
/**
|
|
509
|
+
/**
|
|
510
|
+
* Watches what is drawn for size, re-observing only when that changed.
|
|
511
|
+
*
|
|
512
|
+
* **In the next frame's animation callbacks, never in the update that asked.**
|
|
513
|
+
* A resize notice asks for an update, the update draws new turns while the
|
|
514
|
+
* browser is still delivering notices, and turns observed then are held to
|
|
515
|
+
* the next frame with "ResizeObserver loop completed with undelivered
|
|
516
|
+
* notifications": twice in WebKit's run of Chat's specs and once in
|
|
517
|
+
* Chromium's, on October 11, 2026. Observed from the next frame's callbacks,
|
|
518
|
+
* their first notice comes before that frame paints, and a turn drawn for the
|
|
519
|
+
* first time is answered sooner still, by `settleDrawn`.
|
|
520
|
+
*/
|
|
500
521
|
private watchSizes;
|
|
522
|
+
/** Observes the log and the turns drawn now, where that changed. */
|
|
523
|
+
private observeSizes;
|
|
524
|
+
/**
|
|
525
|
+
* Answers the turns this render drew for the first time, once each has drawn
|
|
526
|
+
* what is in it: a microtask after this update, and before the frame.
|
|
527
|
+
*
|
|
528
|
+
* **Sooner than the resize observer, which `watchSizes` starts a frame
|
|
529
|
+
* later.** A turn is drawn empty and fills in after this update, and until
|
|
530
|
+
* it is measured the reader's turn sits where the estimates put it. A timer
|
|
531
|
+
* that ran before the next frame read that place as the reader's: on a Linux
|
|
532
|
+
* runner, the controller's rest after a scroll left a reader's turn 55.5
|
|
533
|
+
* pixels from where it was when history arrived above it, in WebKit, on
|
|
534
|
+
* October 11, 2026. Answered here, the history is held before any timer runs.
|
|
535
|
+
*/
|
|
536
|
+
private settleDrawn;
|
|
501
537
|
/**
|
|
502
538
|
* A turn or the log changed size, which moves nothing on its own.
|
|
503
539
|
*
|
|
@@ -62,6 +62,7 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
62
62
|
this.settling = undefined;
|
|
63
63
|
this.grower = undefined;
|
|
64
64
|
this.watched = [];
|
|
65
|
+
this.watchFrame = 0;
|
|
65
66
|
this.stuckAt = -1;
|
|
66
67
|
this.anchor = undefined;
|
|
67
68
|
this.asked = false;
|
|
@@ -259,7 +260,12 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
259
260
|
stick() {
|
|
260
261
|
const log = this.log;
|
|
261
262
|
if (log) {
|
|
262
|
-
log.
|
|
263
|
+
if (typeof log.scrollTo === 'function') {
|
|
264
|
+
log.scrollTo({ behavior: 'instant', top: log.scrollHeight });
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
log.scrollTop = log.scrollHeight;
|
|
268
|
+
}
|
|
263
269
|
this.stuckAt = log.scrollTop;
|
|
264
270
|
}
|
|
265
271
|
}
|
|
@@ -335,7 +341,7 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
335
341
|
}
|
|
336
342
|
const found = turns[low];
|
|
337
343
|
this.anchor = found
|
|
338
|
-
? { id: found.id, offset: found.element.getBoundingClientRect().top - top }
|
|
344
|
+
? { at: log.scrollTop, id: found.id, offset: found.element.getBoundingClientRect().top - top }
|
|
339
345
|
: undefined;
|
|
340
346
|
}
|
|
341
347
|
restore() {
|
|
@@ -344,6 +350,10 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
344
350
|
if (!log || !anchor || (this.fed && this.virtualize.scrolling())) {
|
|
345
351
|
return;
|
|
346
352
|
}
|
|
353
|
+
if (!this.fed && Math.abs(log.scrollTop - anchor.at) >= 1) {
|
|
354
|
+
this.remember();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
347
357
|
const found = this.rendered().find((turn) => turn.id === anchor.id);
|
|
348
358
|
if (!found) {
|
|
349
359
|
return;
|
|
@@ -418,9 +428,21 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
418
428
|
: formatWords(this, 'arrivalLabel', { author: turn.by, text: turn.text });
|
|
419
429
|
}
|
|
420
430
|
watchSizes() {
|
|
421
|
-
if (typeof ResizeObserver === 'undefined') {
|
|
431
|
+
if (typeof ResizeObserver === 'undefined' || this.watchFrame !== 0) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (typeof requestAnimationFrame !== 'function') {
|
|
435
|
+
this.observeSizes();
|
|
422
436
|
return;
|
|
423
437
|
}
|
|
438
|
+
this.watchFrame = requestAnimationFrame(() => {
|
|
439
|
+
this.watchFrame = 0;
|
|
440
|
+
if (this.isConnected) {
|
|
441
|
+
this.observeSizes();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
observeSizes() {
|
|
424
446
|
const log = this.log;
|
|
425
447
|
const targets = [...(log ? [log] : []), ...this.rendered().map((turn) => turn.element)];
|
|
426
448
|
if (targets.length === this.watched.length &&
|
|
@@ -434,6 +456,18 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
434
456
|
}
|
|
435
457
|
this.watched = targets;
|
|
436
458
|
}
|
|
459
|
+
settleDrawn() {
|
|
460
|
+
const waiting = this.drawn().filter((row) => !drawnInFull(row));
|
|
461
|
+
if (waiting.length === 0) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
void Promise.all(waiting.map(({ element }) => element.firstElementChild
|
|
465
|
+
?.updateComplete)).then(() => {
|
|
466
|
+
if (this.isConnected && this.fed) {
|
|
467
|
+
this.handleResize();
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
437
471
|
connectedCallback() {
|
|
438
472
|
super.connectedCallback();
|
|
439
473
|
this.addEventListener('keydown', this.handleKeydown);
|
|
@@ -458,6 +492,10 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
458
492
|
this.settling = undefined;
|
|
459
493
|
this.grower?.disconnect();
|
|
460
494
|
this.watched = [];
|
|
495
|
+
if (this.watchFrame !== 0) {
|
|
496
|
+
cancelAnimationFrame(this.watchFrame);
|
|
497
|
+
this.watchFrame = 0;
|
|
498
|
+
}
|
|
461
499
|
}
|
|
462
500
|
willUpdate(changed) {
|
|
463
501
|
super.willUpdate(changed);
|
|
@@ -518,6 +556,7 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
518
556
|
}
|
|
519
557
|
if (this.fed) {
|
|
520
558
|
this.virtualize.measure();
|
|
559
|
+
this.settleDrawn();
|
|
521
560
|
}
|
|
522
561
|
this.watchSizes();
|
|
523
562
|
this.markScroller();
|