@kodaris/krubble-app-components 1.0.147 → 1.0.148
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/chatbot.d.ts +17 -0
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +73 -1
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +85 -3
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +13 -5
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +85 -3
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +14 -6
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/dist/screen-nav.d.ts +13 -2
- package/dist/screen-nav.d.ts.map +1 -1
- package/dist/screen-nav.js +12 -2
- package/dist/screen-nav.js.map +1 -1
- package/package.json +1 -1
|
@@ -2897,6 +2897,13 @@ class KRChatbot extends i$3 {
|
|
|
2897
2897
|
*/
|
|
2898
2898
|
this._reconnectAttempts = 0;
|
|
2899
2899
|
this._userHasScrolledUp = false;
|
|
2900
|
+
/**
|
|
2901
|
+
* Keep the end of the streaming response in view. Set at the start of every
|
|
2902
|
+
* turn (send, confirmation decision, reconnect); cleared when the user scrolls
|
|
2903
|
+
* up on their own (wheel, touch drag, scrollbar drag) and restored when they
|
|
2904
|
+
* scroll back to the bottom. Checked in updated() after every streamed chunk.
|
|
2905
|
+
*/
|
|
2906
|
+
this._followStream = false;
|
|
2900
2907
|
this._isDragging = false;
|
|
2901
2908
|
this._isResizing = false;
|
|
2902
2909
|
this._overlay = null;
|
|
@@ -3552,6 +3559,35 @@ class KRChatbot extends i$3 {
|
|
|
3552
3559
|
});
|
|
3553
3560
|
}
|
|
3554
3561
|
}
|
|
3562
|
+
// Streamed chunks mutate the message in place and call requestUpdate(), so
|
|
3563
|
+
// `changed` never has 'messages' mid-turn — run the follow on every update
|
|
3564
|
+
// instead. The user message stays pinned at the top (Gemini-style) until the
|
|
3565
|
+
// response grows past the bottom of the view; from then on the end stays in
|
|
3566
|
+
// view. Never scrolls to the empty runway below the content.
|
|
3567
|
+
if (this._isStreaming && this._followStream && this._messagesEl) {
|
|
3568
|
+
requestAnimationFrame(() => {
|
|
3569
|
+
const container = this._messagesEl;
|
|
3570
|
+
if (!container || !this._isStreaming || !this._followStream) {
|
|
3571
|
+
return;
|
|
3572
|
+
}
|
|
3573
|
+
const turnEls = container.querySelectorAll('.agent-turn');
|
|
3574
|
+
const turnEl = turnEls[turnEls.length - 1];
|
|
3575
|
+
const lastEl = turnEl?.lastElementChild;
|
|
3576
|
+
if (!lastEl) {
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
// Bottom edge of the turn's last rendered child, in the container's
|
|
3580
|
+
// scroll coordinates — the runway (min-height on the turn) sits below it.
|
|
3581
|
+
const contentBottom = lastEl.getBoundingClientRect().bottom
|
|
3582
|
+
- container.getBoundingClientRect().top
|
|
3583
|
+
+ container.scrollTop
|
|
3584
|
+
+ 24;
|
|
3585
|
+
const visibleBottom = container.scrollTop + container.clientHeight;
|
|
3586
|
+
if (contentBottom > visibleBottom) {
|
|
3587
|
+
container.scrollTop = Math.min(contentBottom - container.clientHeight, container.scrollHeight - container.clientHeight);
|
|
3588
|
+
}
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3555
3591
|
if (changed.has('opened') && this.opened && this._inputEl) {
|
|
3556
3592
|
setTimeout(() => {
|
|
3557
3593
|
if (this._inputEl) {
|
|
@@ -4620,6 +4656,7 @@ class KRChatbot extends i$3 {
|
|
|
4620
4656
|
this._saveState();
|
|
4621
4657
|
this._error = '';
|
|
4622
4658
|
this._userHasScrolledUp = false;
|
|
4659
|
+
this._followStream = true;
|
|
4623
4660
|
// Clear the composer, but DON'T revoke the preview object URLs — the sent
|
|
4624
4661
|
// message now renders them until the upload's real files replace them.
|
|
4625
4662
|
this._pendingConversationFiles = [];
|
|
@@ -4854,6 +4891,7 @@ class KRChatbot extends i$3 {
|
|
|
4854
4891
|
this._turnFinishedCleanly = false;
|
|
4855
4892
|
this._reconnectAttempts = 0;
|
|
4856
4893
|
this._userHasScrolledUp = false;
|
|
4894
|
+
this._followStream = true;
|
|
4857
4895
|
this.send({
|
|
4858
4896
|
message: '',
|
|
4859
4897
|
messages: this.messages,
|
|
@@ -4954,6 +4992,33 @@ class KRChatbot extends i$3 {
|
|
|
4954
4992
|
}
|
|
4955
4993
|
else {
|
|
4956
4994
|
this._userHasScrolledUp = false;
|
|
4995
|
+
// Back at the bottom mid-turn: resume following the stream end.
|
|
4996
|
+
if (this._isStreaming) {
|
|
4997
|
+
this._followStream = true;
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
/**
|
|
5002
|
+
* User-driven scroll intent while a response streams. Scroll events alone can't
|
|
5003
|
+
* tell the user apart from our own follow-scroll (and from scrollTop clamping
|
|
5004
|
+
* when the runway clears), so listen for the gestures instead: a wheel/trackpad
|
|
5005
|
+
* move up, any touch drag, or a pointer down on the scrollbar track. Any of
|
|
5006
|
+
* these stops the follow; scrolling back to the bottom restores it.
|
|
5007
|
+
*/
|
|
5008
|
+
_handleMessagesWheel(e) {
|
|
5009
|
+
if (this._isStreaming && e.deltaY < 0) {
|
|
5010
|
+
this._followStream = false;
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
_handleMessagesTouchMove() {
|
|
5014
|
+
if (this._isStreaming) {
|
|
5015
|
+
this._followStream = false;
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
_handleMessagesPointerDown(e) {
|
|
5019
|
+
const container = e.currentTarget;
|
|
5020
|
+
if (this._isStreaming && e.offsetX >= container.clientWidth) {
|
|
5021
|
+
this._followStream = false;
|
|
4957
5022
|
}
|
|
4958
5023
|
}
|
|
4959
5024
|
_handleErrorDismiss() {
|
|
@@ -5526,6 +5591,7 @@ class KRChatbot extends i$3 {
|
|
|
5526
5591
|
// (a no-op).
|
|
5527
5592
|
this._reconnectAttempts = 0;
|
|
5528
5593
|
this._isStreaming = true;
|
|
5594
|
+
this._followStream = true;
|
|
5529
5595
|
this._reader = response.body.getReader();
|
|
5530
5596
|
this._decoder = new TextDecoder();
|
|
5531
5597
|
this._buffer = '';
|
|
@@ -6644,7 +6710,13 @@ class KRChatbot extends i$3 {
|
|
|
6644
6710
|
</div>
|
|
6645
6711
|
</div>
|
|
6646
6712
|
|
|
6647
|
-
<div
|
|
6713
|
+
<div
|
|
6714
|
+
class="messages"
|
|
6715
|
+
@scroll=${this._handleMessagesScroll}
|
|
6716
|
+
@wheel=${this._handleMessagesWheel}
|
|
6717
|
+
@touchmove=${this._handleMessagesTouchMove}
|
|
6718
|
+
@pointerdown=${this._handleMessagesPointerDown}
|
|
6719
|
+
>
|
|
6648
6720
|
<div class="messages-inner">
|
|
6649
6721
|
${this.messages.length === 0 ? b `
|
|
6650
6722
|
<div class="empty">
|
|
@@ -11544,6 +11616,7 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
11544
11616
|
* activeId="overview"
|
|
11545
11617
|
* .actions=${[
|
|
11546
11618
|
* { id: 'edit', label: 'Edit', variant: 'flat' },
|
|
11619
|
+
* { id: 'preview', label: 'Preview', href: '/s/companies/123', target: '_blank' },
|
|
11547
11620
|
* { id: 'archive', label: 'Archive' },
|
|
11548
11621
|
* { id: 'delete', label: 'Delete' },
|
|
11549
11622
|
* { id: 'export', label: 'Export' },
|
|
@@ -11555,7 +11628,8 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
11555
11628
|
*
|
|
11556
11629
|
* Actions render in a footer at the bottom of the nav column. With more than
|
|
11557
11630
|
* `maxVisibleActions` (default 5), the overflow collapses into a "More" dropdown.
|
|
11558
|
-
* Listen for `action-click` to handle a click: `e.detail.action` is the action id.
|
|
11631
|
+
* Listen for `action-click` to handle a click: `e.detail.action` is the action id. An action with
|
|
11632
|
+
* an `href` renders as a link and navigates on its own; it does not fire `action-click`.
|
|
11559
11633
|
*
|
|
11560
11634
|
* @slot - The main screen content
|
|
11561
11635
|
*
|
|
@@ -11566,7 +11640,7 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
11566
11640
|
* @property {KRScreenNavAction[]} actions - Action buttons rendered in the nav footer
|
|
11567
11641
|
* @property {number} maxVisibleActions - Max inline actions before collapsing into a "More" dropdown (default 5)
|
|
11568
11642
|
*
|
|
11569
|
-
* @fires action-click - When an action button (inline or overflow) is clicked; detail is `{ action: id }`
|
|
11643
|
+
* @fires action-click - When an action button (inline or overflow) without an `href` is clicked; detail is `{ action: id }`
|
|
11570
11644
|
*/
|
|
11571
11645
|
class KRScreenNav extends i$3 {
|
|
11572
11646
|
constructor() {
|
|
@@ -11660,6 +11734,10 @@ class KRScreenNav extends i$3 {
|
|
|
11660
11734
|
}
|
|
11661
11735
|
}
|
|
11662
11736
|
handleActionClick(e, action) {
|
|
11737
|
+
// A link action navigates on its own through the kr-button's anchor; it doesn't fire action-click.
|
|
11738
|
+
if (action.href) {
|
|
11739
|
+
return;
|
|
11740
|
+
}
|
|
11663
11741
|
this.dispatchEvent(new CustomEvent('action-click', {
|
|
11664
11742
|
detail: { action: action.id },
|
|
11665
11743
|
bubbles: true,
|
|
@@ -11686,6 +11764,8 @@ class KRScreenNav extends i$3 {
|
|
|
11686
11764
|
overflowOptions = this.actions.slice(this.maxVisibleActions - 1).map((action) => ({
|
|
11687
11765
|
id: action.id,
|
|
11688
11766
|
label: action.label,
|
|
11767
|
+
href: action.href,
|
|
11768
|
+
hrefTarget: action.target,
|
|
11689
11769
|
}));
|
|
11690
11770
|
}
|
|
11691
11771
|
return b `
|
|
@@ -11721,6 +11801,8 @@ class KRScreenNav extends i$3 {
|
|
|
11721
11801
|
class="nav-actions__button"
|
|
11722
11802
|
variant=${action.variant || 'outline'}
|
|
11723
11803
|
size="small"
|
|
11804
|
+
href=${action.href || A}
|
|
11805
|
+
target=${action.target || A}
|
|
11724
11806
|
@click=${(e) => this.handleActionClick(e, action)}
|
|
11725
11807
|
>
|
|
11726
11808
|
${action.label}
|