@ni/spright-components 6.20.4 → 6.21.1
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/all-components-bundle.js +364 -3
- package/dist/all-components-bundle.js.map +1 -1
- package/dist/all-components-bundle.min.js +3202 -3138
- package/dist/all-components-bundle.min.js.map +1 -1
- package/dist/custom-elements.json +51 -0
- package/dist/custom-elements.md +10 -6
- package/dist/esm/chat/conversation/index.d.ts +22 -0
- package/dist/esm/chat/conversation/index.js +47 -0
- package/dist/esm/chat/conversation/index.js.map +1 -1
- package/dist/esm/chat/conversation/models/auto-scroll-manager.d.ts +53 -0
- package/dist/esm/chat/conversation/models/auto-scroll-manager.js +222 -0
- package/dist/esm/chat/conversation/models/auto-scroll-manager.js.map +1 -0
- package/dist/esm/chat/conversation/styles.js +18 -1
- package/dist/esm/chat/conversation/styles.js.map +1 -1
- package/dist/esm/chat/conversation/template.js +9 -2
- package/dist/esm/chat/conversation/template.js.map +1 -1
- package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.d.ts +55 -0
- package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.js +194 -0
- package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.js.map +1 -0
- package/dist/esm/chat/message/inbound/index.d.ts +3 -0
- package/dist/esm/chat/message/inbound/index.js +3 -0
- package/dist/esm/chat/message/inbound/index.js.map +1 -1
- package/dist/esm/chat/message/models/chat-message-internals.d.ts +38 -0
- package/dist/esm/chat/message/models/chat-message-internals.js +39 -0
- package/dist/esm/chat/message/models/chat-message-internals.js.map +1 -0
- package/dist/esm/chat/message/outbound/index.d.ts +3 -0
- package/dist/esm/chat/message/outbound/index.js +8 -0
- package/dist/esm/chat/message/outbound/index.js.map +1 -1
- package/dist/esm/chat/message/system/index.d.ts +3 -0
- package/dist/esm/chat/message/system/index.js +6 -0
- package/dist/esm/chat/message/system/index.js.map +1 -1
- package/dist/esm/chat/message/testing/chat-message.pageobject.d.ts +18 -0
- package/dist/esm/chat/message/testing/chat-message.pageobject.js +27 -0
- package/dist/esm/chat/message/testing/chat-message.pageobject.js.map +1 -0
- package/package.json +2 -2
|
@@ -22242,6 +22242,7 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
22242
22242
|
${styles$$}
|
|
22243
22243
|
|
|
22244
22244
|
:host {
|
|
22245
|
+
field-sizing: fixed;
|
|
22245
22246
|
--ni-private-hover-bottom-border-width: 2px;
|
|
22246
22247
|
--ni-private-bottom-border-width: 1px;
|
|
22247
22248
|
--ni-private-height-within-border: calc(
|
|
@@ -22250,6 +22251,7 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
22250
22251
|
}
|
|
22251
22252
|
|
|
22252
22253
|
.control {
|
|
22254
|
+
field-sizing: inherit;
|
|
22253
22255
|
bottom-border-width: var(--ni-private-bottom-border-width);
|
|
22254
22256
|
}
|
|
22255
22257
|
|
|
@@ -22257,7 +22259,12 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
22257
22259
|
border-bottom-color: ${borderHoverColor};
|
|
22258
22260
|
}
|
|
22259
22261
|
|
|
22262
|
+
slot[name='control'] {
|
|
22263
|
+
field-sizing: inherit;
|
|
22264
|
+
}
|
|
22265
|
+
|
|
22260
22266
|
.selected-value {
|
|
22267
|
+
field-sizing: inherit;
|
|
22261
22268
|
-webkit-appearance: none;
|
|
22262
22269
|
background: transparent;
|
|
22263
22270
|
border: none;
|
|
@@ -28107,6 +28114,7 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
28107
28114
|
outline: none;
|
|
28108
28115
|
${userSelectNone}
|
|
28109
28116
|
color: ${bodyFontColor};
|
|
28117
|
+
field-sizing: fixed;
|
|
28110
28118
|
--ni-private-hover-indicator-width: calc(${borderWidth} + 1px);
|
|
28111
28119
|
--ni-private-height-within-border: calc(
|
|
28112
28120
|
${controlHeight} - 2 * ${borderWidth}
|
|
@@ -28139,6 +28147,7 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
28139
28147
|
position: relative;
|
|
28140
28148
|
display: flex;
|
|
28141
28149
|
flex-direction: row;
|
|
28150
|
+
field-sizing: inherit;
|
|
28142
28151
|
justify-content: center;
|
|
28143
28152
|
align-items: center;
|
|
28144
28153
|
border-radius: 0px;
|
|
@@ -28206,12 +28215,17 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
28206
28215
|
font: inherit;
|
|
28207
28216
|
background: transparent;
|
|
28208
28217
|
color: inherit;
|
|
28218
|
+
field-sizing: inherit;
|
|
28209
28219
|
height: var(--ni-private-height-within-border);
|
|
28210
28220
|
width: 100%;
|
|
28211
28221
|
border: none;
|
|
28212
28222
|
padding: 0px;
|
|
28213
28223
|
padding-left: ${mediumPadding};
|
|
28214
28224
|
}
|
|
28225
|
+
|
|
28226
|
+
:host([hide-step]) .control {
|
|
28227
|
+
padding-right: ${smallPadding};
|
|
28228
|
+
}
|
|
28215
28229
|
|
|
28216
28230
|
.control:hover,
|
|
28217
28231
|
.control:focus,
|
|
@@ -28309,6 +28323,7 @@ so this becomes the fallback color for the slot */ ''}
|
|
|
28309
28323
|
|
|
28310
28324
|
:host([full-bleed]) .control {
|
|
28311
28325
|
padding-left: 0px;
|
|
28326
|
+
padding-right: 0px;
|
|
28312
28327
|
}
|
|
28313
28328
|
`));
|
|
28314
28329
|
|
|
@@ -81198,6 +81213,8 @@ focus outline in that case.
|
|
|
81198
81213
|
outline: none;
|
|
81199
81214
|
${userSelectNone}
|
|
81200
81215
|
color: ${bodyFontColor};
|
|
81216
|
+
field-sizing: fixed;
|
|
81217
|
+
min-width: 100px;
|
|
81201
81218
|
flex-direction: column;
|
|
81202
81219
|
vertical-align: top;
|
|
81203
81220
|
--ni-private-hover-indicator-width: calc(${borderWidth} + 1px);
|
|
@@ -81229,6 +81246,7 @@ focus outline in that case.
|
|
|
81229
81246
|
display: flex;
|
|
81230
81247
|
justify-content: center;
|
|
81231
81248
|
position: relative;
|
|
81249
|
+
field-sizing: inherit;
|
|
81232
81250
|
height: 100%;
|
|
81233
81251
|
width: 100%;
|
|
81234
81252
|
}
|
|
@@ -81273,7 +81291,7 @@ focus outline in that case.
|
|
|
81273
81291
|
border-radius: 0px;
|
|
81274
81292
|
align-items: flex-end;
|
|
81275
81293
|
border: ${borderWidth} solid transparent;
|
|
81276
|
-
|
|
81294
|
+
field-sizing: inherit;
|
|
81277
81295
|
min-height: calc(${iconSize} + ${standardPadding});
|
|
81278
81296
|
padding: 8px;
|
|
81279
81297
|
${
|
|
@@ -81559,6 +81577,7 @@ focus outline in that case.
|
|
|
81559
81577
|
outline: none;
|
|
81560
81578
|
${userSelectNone}
|
|
81561
81579
|
color: ${bodyFontColor};
|
|
81580
|
+
field-sizing: fixed;
|
|
81562
81581
|
--ni-private-hover-indicator-width: calc(${borderWidth} + 1px);
|
|
81563
81582
|
--ni-private-height-within-border: calc(
|
|
81564
81583
|
${controlHeight} - 2 * ${borderWidth}
|
|
@@ -81593,6 +81612,7 @@ focus outline in that case.
|
|
|
81593
81612
|
display: flex;
|
|
81594
81613
|
flex-direction: row;
|
|
81595
81614
|
border-radius: 0px;
|
|
81615
|
+
field-sizing: inherit;
|
|
81596
81616
|
font: inherit;
|
|
81597
81617
|
align-items: center;
|
|
81598
81618
|
justify-content: center;
|
|
@@ -81671,6 +81691,7 @@ focus outline in that case.
|
|
|
81671
81691
|
background: transparent;
|
|
81672
81692
|
color: inherit;
|
|
81673
81693
|
padding: 0px;
|
|
81694
|
+
field-sizing: inherit;
|
|
81674
81695
|
height: var(--ni-private-height-within-border);
|
|
81675
81696
|
width: 100%;
|
|
81676
81697
|
margin-top: auto;
|
|
@@ -100078,6 +100099,7 @@ focus outline in that case.
|
|
|
100078
100099
|
${display('flex')}
|
|
100079
100100
|
|
|
100080
100101
|
:host {
|
|
100102
|
+
height: 480px;
|
|
100081
100103
|
flex-direction: column;
|
|
100082
100104
|
background: ${applicationBackgroundColor};
|
|
100083
100105
|
}
|
|
@@ -100125,12 +100147,28 @@ focus outline in that case.
|
|
|
100125
100147
|
flex: 1;
|
|
100126
100148
|
display: flex;
|
|
100127
100149
|
flex-direction: column;
|
|
100128
|
-
justify-content: flex-start;
|
|
100129
100150
|
row-gap: 32px;
|
|
100130
100151
|
padding: ${mediumPadding} ${standardPadding} ${mediumPadding}
|
|
100131
100152
|
${standardPadding};
|
|
100132
100153
|
background: ${sectionBackgroundImage};
|
|
100133
100154
|
overflow-y: auto;
|
|
100155
|
+
overflow-anchor: none;
|
|
100156
|
+
}
|
|
100157
|
+
|
|
100158
|
+
.messages-history,
|
|
100159
|
+
.messages-anchored {
|
|
100160
|
+
flex: none;
|
|
100161
|
+
display: flex;
|
|
100162
|
+
flex-direction: column;
|
|
100163
|
+
row-gap: 32px;
|
|
100164
|
+
}
|
|
100165
|
+
|
|
100166
|
+
.messages-history.region-empty {
|
|
100167
|
+
display: none;
|
|
100168
|
+
}
|
|
100169
|
+
|
|
100170
|
+
.messages-anchored.anchor-active {
|
|
100171
|
+
min-height: 100%;
|
|
100134
100172
|
}
|
|
100135
100173
|
|
|
100136
100174
|
:host([appearance='overlay']) .messages {
|
|
@@ -100154,7 +100192,14 @@ focus outline in that case.
|
|
|
100154
100192
|
<div class="start ${x => (x.startEmpty ? 'start-empty' : '')}">
|
|
100155
100193
|
<slot name="start" ${slotted({ property: 'slottedStartElements' })}></slot>
|
|
100156
100194
|
</div>
|
|
100157
|
-
<div class="messages"
|
|
100195
|
+
<div class="messages" ${ref('messagesContainer')}>
|
|
100196
|
+
<div class="messages-history ${x => (x.historyEmpty ? 'region-empty' : '')}">
|
|
100197
|
+
<slot name="history" ${slotted({ property: 'slottedHistoryMessages' })}></slot>
|
|
100198
|
+
</div>
|
|
100199
|
+
<div class="messages-anchored ${x => (x.autoScrollManager.anchorActive ? 'anchor-active' : '')}" ${ref('anchoredContainer')}>
|
|
100200
|
+
<slot ${slotted({ property: 'slottedMessages' })}></slot>
|
|
100201
|
+
</div>
|
|
100202
|
+
</div>
|
|
100158
100203
|
<div class="input ${x => (x.inputEmpty ? 'input-empty' : '')}">
|
|
100159
100204
|
<slot name="input" ${slotted({ property: 'slottedInputElements' })}>
|
|
100160
100205
|
</slot>
|
|
@@ -100171,6 +100216,262 @@ focus outline in that case.
|
|
|
100171
100216
|
const ChatConversationAppearance = {
|
|
100172
100217
|
default: undefined};
|
|
100173
100218
|
|
|
100219
|
+
/**
|
|
100220
|
+
* Internal state for a chat message
|
|
100221
|
+
* @internal
|
|
100222
|
+
*/
|
|
100223
|
+
class ChatMessageInternals {
|
|
100224
|
+
constructor(host, options) {
|
|
100225
|
+
/**
|
|
100226
|
+
* True when this message is the one the conversation anchors to while
|
|
100227
|
+
* auto-scrolling.
|
|
100228
|
+
*/
|
|
100229
|
+
this.isScrollAnchor = false;
|
|
100230
|
+
this.host = host;
|
|
100231
|
+
this.anchorOnInsert = options?.anchorOnInsert ?? false;
|
|
100232
|
+
}
|
|
100233
|
+
get slot() {
|
|
100234
|
+
return this.slotName;
|
|
100235
|
+
}
|
|
100236
|
+
set slot(value) {
|
|
100237
|
+
if (value === this.slotName) {
|
|
100238
|
+
return;
|
|
100239
|
+
}
|
|
100240
|
+
this.slotName = value;
|
|
100241
|
+
if (value === undefined) {
|
|
100242
|
+
this.host.removeAttribute('slot');
|
|
100243
|
+
}
|
|
100244
|
+
else {
|
|
100245
|
+
this.host.setAttribute('slot', value);
|
|
100246
|
+
}
|
|
100247
|
+
}
|
|
100248
|
+
static elementHasMessageInternals(element) {
|
|
100249
|
+
return element.messageInternals instanceof ChatMessageInternals;
|
|
100250
|
+
}
|
|
100251
|
+
}
|
|
100252
|
+
__decorate([
|
|
100253
|
+
observable
|
|
100254
|
+
], ChatMessageInternals.prototype, "isScrollAnchor", void 0);
|
|
100255
|
+
|
|
100256
|
+
// Distance from the bottom (px) within which the conversation is considered "at the bottom".
|
|
100257
|
+
const scrollingPixelThreshold = 10;
|
|
100258
|
+
// Slot name for messages that precede the current turn's anchor message.
|
|
100259
|
+
const historySlotName = 'history';
|
|
100260
|
+
/**
|
|
100261
|
+
* Manages auto-scroll behavior for the chat conversation:
|
|
100262
|
+
* - Splits messages into `default` and `history` slots so the top message of the
|
|
100263
|
+
* `default` slot becomes the anchor: it is moved to the top of the viewport and scrolled to on insert
|
|
100264
|
+
* - Implements auto scroll when at the bottom of the window as content is added until the user scrolls away
|
|
100265
|
+
* @internal
|
|
100266
|
+
*/
|
|
100267
|
+
class AutoScrollManager {
|
|
100268
|
+
get isActive() {
|
|
100269
|
+
return this.resizeObserver !== undefined;
|
|
100270
|
+
}
|
|
100271
|
+
constructor(conversation) {
|
|
100272
|
+
this.conversation = conversation;
|
|
100273
|
+
/**
|
|
100274
|
+
* Whether auto-scroll is currently following new content. Set to false when
|
|
100275
|
+
* the user scrolls away from the bottom and back to true when they return.
|
|
100276
|
+
*/
|
|
100277
|
+
this.autoScrollEngaged = true;
|
|
100278
|
+
/**
|
|
100279
|
+
* Whether the anchored region is reserving a viewport of space
|
|
100280
|
+
*/
|
|
100281
|
+
this.anchorActive = false;
|
|
100282
|
+
this.scrollUpdatePending = false;
|
|
100283
|
+
this.pendingAnchorInsert = false;
|
|
100284
|
+
this.previousMessages = [];
|
|
100285
|
+
this.onScroll = () => {
|
|
100286
|
+
const container = this.conversation.messagesContainer;
|
|
100287
|
+
if (this.programmaticScrollTarget !== undefined) {
|
|
100288
|
+
// The programmatic scroll always targets the bottom, so treat it as
|
|
100289
|
+
// settled once we reach that target or the bottom itself.
|
|
100290
|
+
const reachedTarget = Math.abs(container.scrollTop - this.programmaticScrollTarget) <= 1;
|
|
100291
|
+
const reachedBottom = this.getDistanceFromBottom() <= scrollingPixelThreshold;
|
|
100292
|
+
if (reachedTarget || reachedBottom) {
|
|
100293
|
+
this.programmaticScrollTarget = undefined;
|
|
100294
|
+
}
|
|
100295
|
+
return;
|
|
100296
|
+
}
|
|
100297
|
+
this.autoScrollEngaged = this.getDistanceFromBottom() <= scrollingPixelThreshold;
|
|
100298
|
+
};
|
|
100299
|
+
this.conversationNotifier = Observable.getNotifier(this.conversation);
|
|
100300
|
+
}
|
|
100301
|
+
connect() {
|
|
100302
|
+
this.autoScrollEngaged = true;
|
|
100303
|
+
this.previousMessages = this.getOrderedMessages();
|
|
100304
|
+
this.conversationNotifier.subscribe(this, 'slottedMessages');
|
|
100305
|
+
this.conversationNotifier.subscribe(this, 'slottedHistoryMessages');
|
|
100306
|
+
this.conversation.messagesContainer.addEventListener('scroll', this.onScroll, { passive: true });
|
|
100307
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
100308
|
+
this.onContentSizeChanged();
|
|
100309
|
+
});
|
|
100310
|
+
// Observe the anchored region for streamed content growth and the scroll
|
|
100311
|
+
// viewport so the conversation stays pinned when its height changes.
|
|
100312
|
+
this.resizeObserver.observe(this.conversation.anchoredContainer);
|
|
100313
|
+
this.resizeObserver.observe(this.conversation.messagesContainer);
|
|
100314
|
+
this.repartition(this.previousMessages);
|
|
100315
|
+
}
|
|
100316
|
+
disconnect() {
|
|
100317
|
+
this.conversationNotifier.unsubscribe(this, 'slottedMessages');
|
|
100318
|
+
this.conversationNotifier.unsubscribe(this, 'slottedHistoryMessages');
|
|
100319
|
+
this.conversation.messagesContainer.removeEventListener('scroll', this.onScroll);
|
|
100320
|
+
this.resizeObserver?.disconnect();
|
|
100321
|
+
this.resizeObserver = undefined;
|
|
100322
|
+
this.setScrollAnchorMessage(undefined);
|
|
100323
|
+
this.clearSlotAssignments();
|
|
100324
|
+
this.anchorActive = false;
|
|
100325
|
+
this.previousMessages = [];
|
|
100326
|
+
}
|
|
100327
|
+
handleChange(source, args) {
|
|
100328
|
+
if (source === this.conversation
|
|
100329
|
+
&& (args === 'slottedMessages' || args === 'slottedHistoryMessages')) {
|
|
100330
|
+
this.onMessagesChanged();
|
|
100331
|
+
}
|
|
100332
|
+
}
|
|
100333
|
+
onMessagesChanged() {
|
|
100334
|
+
const current = this.getOrderedMessages();
|
|
100335
|
+
const previousSet = new Set(this.previousMessages);
|
|
100336
|
+
const addedMessages = current.filter(message => !previousSet.has(message));
|
|
100337
|
+
this.previousMessages = current;
|
|
100338
|
+
this.repartition(current);
|
|
100339
|
+
if (addedMessages.length === 0) {
|
|
100340
|
+
return;
|
|
100341
|
+
}
|
|
100342
|
+
const hasAnchorMessage = addedMessages.some(message => message.messageInternals.anchorOnInsert);
|
|
100343
|
+
this.scheduleScrollUpdate(hasAnchorMessage);
|
|
100344
|
+
}
|
|
100345
|
+
repartition(messages) {
|
|
100346
|
+
const anchorIndex = this.findLatestAnchorIndex(messages);
|
|
100347
|
+
messages.forEach((message, index) => {
|
|
100348
|
+
message.messageInternals.slot = anchorIndex >= 0 && index < anchorIndex
|
|
100349
|
+
? historySlotName
|
|
100350
|
+
: undefined;
|
|
100351
|
+
});
|
|
100352
|
+
this.anchorActive = anchorIndex >= 0;
|
|
100353
|
+
}
|
|
100354
|
+
clearSlotAssignments() {
|
|
100355
|
+
for (const message of this.getOrderedMessages()) {
|
|
100356
|
+
message.messageInternals.slot = undefined;
|
|
100357
|
+
}
|
|
100358
|
+
}
|
|
100359
|
+
scheduleScrollUpdate(hasAnchorMessage) {
|
|
100360
|
+
this.pendingAnchorInsert = this.pendingAnchorInsert || hasAnchorMessage;
|
|
100361
|
+
if (this.scrollUpdatePending) {
|
|
100362
|
+
return;
|
|
100363
|
+
}
|
|
100364
|
+
this.scrollUpdatePending = true;
|
|
100365
|
+
requestAnimationFrame(() => {
|
|
100366
|
+
this.scrollUpdatePending = false;
|
|
100367
|
+
const anchorInsert = this.pendingAnchorInsert;
|
|
100368
|
+
this.pendingAnchorInsert = false;
|
|
100369
|
+
if (anchorInsert) {
|
|
100370
|
+
this.anchorToLastInsertedMessage();
|
|
100371
|
+
}
|
|
100372
|
+
else if (this.autoScrollEngaged) {
|
|
100373
|
+
this.followContent();
|
|
100374
|
+
}
|
|
100375
|
+
});
|
|
100376
|
+
}
|
|
100377
|
+
/**
|
|
100378
|
+
* Pins the most recently inserted anchor message near the top of the
|
|
100379
|
+
* viewport.
|
|
100380
|
+
*/
|
|
100381
|
+
anchorToLastInsertedMessage() {
|
|
100382
|
+
const message = this.getLastAnchorMessage();
|
|
100383
|
+
if (message === undefined) {
|
|
100384
|
+
return;
|
|
100385
|
+
}
|
|
100386
|
+
this.setScrollAnchorMessage(message);
|
|
100387
|
+
this.autoScrollEngaged = true;
|
|
100388
|
+
this.smoothScrollTo(this.getMaxScrollTop());
|
|
100389
|
+
}
|
|
100390
|
+
followContent() {
|
|
100391
|
+
this.instantScrollTo(this.getMaxScrollTop());
|
|
100392
|
+
}
|
|
100393
|
+
onContentSizeChanged() {
|
|
100394
|
+
// Reacts to streamed content growth and viewport height changes.
|
|
100395
|
+
// While a pending or in-progress anchor insert owns positioning, let its
|
|
100396
|
+
// smooth scroll settle instead of competing with an instant follow.
|
|
100397
|
+
if (this.pendingAnchorInsert
|
|
100398
|
+
|| this.programmaticScrollTarget !== undefined) {
|
|
100399
|
+
return;
|
|
100400
|
+
}
|
|
100401
|
+
if (this.autoScrollEngaged) {
|
|
100402
|
+
this.followContent();
|
|
100403
|
+
}
|
|
100404
|
+
}
|
|
100405
|
+
getDistanceFromBottom() {
|
|
100406
|
+
const { scrollTop, scrollHeight, clientHeight } = this.conversation.messagesContainer;
|
|
100407
|
+
return scrollHeight - scrollTop - clientHeight;
|
|
100408
|
+
}
|
|
100409
|
+
getMaxScrollTop() {
|
|
100410
|
+
const { scrollHeight, clientHeight } = this.conversation.messagesContainer;
|
|
100411
|
+
return Math.max(0, scrollHeight - clientHeight);
|
|
100412
|
+
}
|
|
100413
|
+
smoothScrollTo(scrollTop) {
|
|
100414
|
+
const container = this.conversation.messagesContainer;
|
|
100415
|
+
if (Math.abs(container.scrollTop - scrollTop) <= 1) {
|
|
100416
|
+
// No movement is needed, so `scrollTo` would not emit a scroll event
|
|
100417
|
+
// to clear the programmatic guard. Snap to the exact target and
|
|
100418
|
+
// leave the guard clear so streamed content keeps being followed.
|
|
100419
|
+
this.programmaticScrollTarget = undefined;
|
|
100420
|
+
container.scrollTop = scrollTop;
|
|
100421
|
+
return;
|
|
100422
|
+
}
|
|
100423
|
+
this.programmaticScrollTarget = scrollTop;
|
|
100424
|
+
container.scrollTo({
|
|
100425
|
+
top: scrollTop,
|
|
100426
|
+
behavior: 'smooth'
|
|
100427
|
+
});
|
|
100428
|
+
}
|
|
100429
|
+
instantScrollTo(scrollTop) {
|
|
100430
|
+
this.conversation.messagesContainer.scrollTop = scrollTop;
|
|
100431
|
+
}
|
|
100432
|
+
setScrollAnchorMessage(message) {
|
|
100433
|
+
if (this.scrollAnchorMessage === message) {
|
|
100434
|
+
return;
|
|
100435
|
+
}
|
|
100436
|
+
if (this.scrollAnchorMessage !== undefined) {
|
|
100437
|
+
this.scrollAnchorMessage.messageInternals.isScrollAnchor = false;
|
|
100438
|
+
}
|
|
100439
|
+
this.scrollAnchorMessage = message;
|
|
100440
|
+
if (message !== undefined) {
|
|
100441
|
+
message.messageInternals.isScrollAnchor = true;
|
|
100442
|
+
}
|
|
100443
|
+
}
|
|
100444
|
+
getLastAnchorMessage() {
|
|
100445
|
+
const messages = this.getOrderedMessages();
|
|
100446
|
+
const index = this.findLatestAnchorIndex(messages);
|
|
100447
|
+
return index >= 0 ? messages[index] : undefined;
|
|
100448
|
+
}
|
|
100449
|
+
findLatestAnchorIndex(messages) {
|
|
100450
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
100451
|
+
const message = messages[i];
|
|
100452
|
+
if (message?.messageInternals.anchorOnInsert) {
|
|
100453
|
+
return i;
|
|
100454
|
+
}
|
|
100455
|
+
}
|
|
100456
|
+
return -1;
|
|
100457
|
+
}
|
|
100458
|
+
getOrderedMessages() {
|
|
100459
|
+
const messages = [];
|
|
100460
|
+
for (const child of Array.from(this.conversation.children)) {
|
|
100461
|
+
if (ChatMessageInternals.elementHasMessageInternals(child)) {
|
|
100462
|
+
messages.push(child);
|
|
100463
|
+
}
|
|
100464
|
+
}
|
|
100465
|
+
return messages;
|
|
100466
|
+
}
|
|
100467
|
+
}
|
|
100468
|
+
__decorate([
|
|
100469
|
+
observable
|
|
100470
|
+
], AutoScrollManager.prototype, "autoScrollEngaged", void 0);
|
|
100471
|
+
__decorate([
|
|
100472
|
+
observable
|
|
100473
|
+
], AutoScrollManager.prototype, "anchorActive", void 0);
|
|
100474
|
+
|
|
100174
100475
|
/**
|
|
100175
100476
|
* A Spright component for displaying a series of chat messages
|
|
100176
100477
|
*/
|
|
@@ -100178,6 +100479,15 @@ focus outline in that case.
|
|
|
100178
100479
|
constructor() {
|
|
100179
100480
|
super(...arguments);
|
|
100180
100481
|
this.appearance = ChatConversationAppearance.default;
|
|
100482
|
+
this.autoScroll = false;
|
|
100483
|
+
/**
|
|
100484
|
+
* Manages auto-scroll behavior. Always present; its observers are registered
|
|
100485
|
+
* while the conversation is connected and `autoScroll` is enabled.
|
|
100486
|
+
* @internal
|
|
100487
|
+
*/
|
|
100488
|
+
this.autoScrollManager = new AutoScrollManager(this);
|
|
100489
|
+
/** @internal */
|
|
100490
|
+
this.historyEmpty = true;
|
|
100181
100491
|
/** @internal */
|
|
100182
100492
|
this.inputEmpty = true;
|
|
100183
100493
|
/** @internal */
|
|
@@ -100187,6 +100497,31 @@ focus outline in that case.
|
|
|
100187
100497
|
/** @internal */
|
|
100188
100498
|
this.endEmpty = true;
|
|
100189
100499
|
}
|
|
100500
|
+
connectedCallback() {
|
|
100501
|
+
super.connectedCallback();
|
|
100502
|
+
if (this.autoScroll) {
|
|
100503
|
+
this.autoScrollManager.connect();
|
|
100504
|
+
}
|
|
100505
|
+
}
|
|
100506
|
+
disconnectedCallback() {
|
|
100507
|
+
super.disconnectedCallback();
|
|
100508
|
+
if (this.autoScroll) {
|
|
100509
|
+
this.autoScrollManager.disconnect();
|
|
100510
|
+
}
|
|
100511
|
+
}
|
|
100512
|
+
autoScrollChanged() {
|
|
100513
|
+
if (this.$fastController.isConnected) {
|
|
100514
|
+
if (this.autoScroll) {
|
|
100515
|
+
this.autoScrollManager.connect();
|
|
100516
|
+
}
|
|
100517
|
+
else {
|
|
100518
|
+
this.autoScrollManager.disconnect();
|
|
100519
|
+
}
|
|
100520
|
+
}
|
|
100521
|
+
}
|
|
100522
|
+
slottedHistoryMessagesChanged(_prev, next) {
|
|
100523
|
+
this.historyEmpty = next === undefined || next.length === 0;
|
|
100524
|
+
}
|
|
100190
100525
|
slottedInputElementsChanged(_prev, next) {
|
|
100191
100526
|
this.inputEmpty = next === undefined || next.length === 0;
|
|
100192
100527
|
}
|
|
@@ -100203,6 +100538,18 @@ focus outline in that case.
|
|
|
100203
100538
|
__decorate([
|
|
100204
100539
|
attr
|
|
100205
100540
|
], ChatConversation.prototype, "appearance", void 0);
|
|
100541
|
+
__decorate([
|
|
100542
|
+
attr({ attribute: 'auto-scroll', mode: 'boolean' })
|
|
100543
|
+
], ChatConversation.prototype, "autoScroll", void 0);
|
|
100544
|
+
__decorate([
|
|
100545
|
+
observable
|
|
100546
|
+
], ChatConversation.prototype, "slottedMessages", void 0);
|
|
100547
|
+
__decorate([
|
|
100548
|
+
observable
|
|
100549
|
+
], ChatConversation.prototype, "slottedHistoryMessages", void 0);
|
|
100550
|
+
__decorate([
|
|
100551
|
+
observable
|
|
100552
|
+
], ChatConversation.prototype, "historyEmpty", void 0);
|
|
100206
100553
|
__decorate([
|
|
100207
100554
|
observable
|
|
100208
100555
|
], ChatConversation.prototype, "inputEmpty", void 0);
|
|
@@ -100862,6 +101209,8 @@ focus outline in that case.
|
|
|
100862
101209
|
constructor() {
|
|
100863
101210
|
super(...arguments);
|
|
100864
101211
|
/** @internal */
|
|
101212
|
+
this.messageInternals = new ChatMessageInternals(this);
|
|
101213
|
+
/** @internal */
|
|
100865
101214
|
this.footerActionsIsEmpty = true;
|
|
100866
101215
|
}
|
|
100867
101216
|
slottedFooterActionsElementsChanged(_prev, next) {
|
|
@@ -100928,6 +101277,13 @@ focus outline in that case.
|
|
|
100928
101277
|
* A Spright component for displaying an outbound chat message
|
|
100929
101278
|
*/
|
|
100930
101279
|
class ChatMessageOutbound extends FoundationElement {
|
|
101280
|
+
constructor() {
|
|
101281
|
+
super(...arguments);
|
|
101282
|
+
/** @internal */
|
|
101283
|
+
this.messageInternals = new ChatMessageInternals(this, {
|
|
101284
|
+
anchorOnInsert: true
|
|
101285
|
+
});
|
|
101286
|
+
}
|
|
100931
101287
|
}
|
|
100932
101288
|
const sprightChatMessageOutbound = ChatMessageOutbound.compose({
|
|
100933
101289
|
baseName: 'chat-message-outbound',
|
|
@@ -100975,6 +101331,11 @@ focus outline in that case.
|
|
|
100975
101331
|
* A Spright component for displaying an system chat message
|
|
100976
101332
|
*/
|
|
100977
101333
|
class ChatMessageSystem extends FoundationElement {
|
|
101334
|
+
constructor() {
|
|
101335
|
+
super(...arguments);
|
|
101336
|
+
/** @internal */
|
|
101337
|
+
this.messageInternals = new ChatMessageInternals(this);
|
|
101338
|
+
}
|
|
100978
101339
|
}
|
|
100979
101340
|
const sprightChatMessageSystem = ChatMessageSystem.compose({
|
|
100980
101341
|
baseName: 'chat-message-system',
|