@progress/kendo-angular-conversational-ui 24.0.0-develop.3 → 24.0.0-develop.30
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/NOTICE.txt +2599 -172
- package/chat/api/chat-load-more-event.d.ts +18 -0
- package/chat/api/chat-referenced-message-click-event.d.ts +18 -0
- package/chat/api/index.d.ts +4 -0
- package/chat/api/scroll-mode.d.ts +12 -0
- package/chat/chat.component.d.ts +142 -2
- package/chat/common/chat.service.d.ts +12 -3
- package/chat/common/endless-scroll-state.d.ts +36 -0
- package/chat/common/models/pending-scroll-action.d.ts +11 -0
- package/chat/common/scroll-anchor.directive.d.ts +38 -1
- package/chat/common/utils.d.ts +15 -0
- package/chat/message.component.d.ts +4 -2
- package/fesm2022/progress-kendo-angular-conversational-ui.mjs +1240 -144
- package/inline-ai-prompt/inlineaiprompt.component.d.ts +1 -1
- package/package-metadata.mjs +2 -2
- package/package.json +14 -14
- package/promptbox/affixes/promptbox-end-affix.component.d.ts +1 -1
- package/promptbox/affixes/promptbox-start-affix.component.d.ts +1 -1
- package/promptbox/affixes/promptbox-top-affix.component.d.ts +1 -1
- package/promptbox/tools/action-button.component.d.ts +2 -2
|
@@ -7,11 +7,11 @@ import { InjectionToken, Input, ViewChild, HostBinding, Inject, Directive, Injec
|
|
|
7
7
|
import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
|
|
8
8
|
import * as i1$2 from '@progress/kendo-angular-popup';
|
|
9
9
|
import { PopupComponent, KENDO_POPUP, PopupService } from '@progress/kendo-angular-popup';
|
|
10
|
-
import { isPresent, normalizeKeys, Keys, focusableSelector, guid, getter, isDocumentAvailable, hasObservers, EventsOutsideAngularDirective, closest as closest$1, ResizeSensorComponent, isChanged, processCssValue, ResizeBatchService } from '@progress/kendo-angular-common';
|
|
10
|
+
import { isPresent, normalizeKeys, Keys, focusableSelector, guid, getter, isDocumentAvailable, hasObservers, EventsOutsideAngularDirective, closest as closest$1, ResizeSensorComponent, getLicenseMessage, shouldShowValidationUI, isChanged, processCssValue, WatermarkOverlayComponent, ResizeBatchService } from '@progress/kendo-angular-common';
|
|
11
11
|
import { DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
|
|
12
12
|
import { NgTemplateOutlet, NgClass } from '@angular/common';
|
|
13
13
|
import { Subject, Subscription, fromEvent } from 'rxjs';
|
|
14
|
-
import { moreHorizontalIcon, commentIcon, sparklesIcon,
|
|
14
|
+
import { moreHorizontalIcon, commentIcon, sparklesIcon, stopIcon, thumbUpIcon, thumbDownIcon, copyIcon, arrowRotateCwIcon, chevronUpIcon, chevronDownIcon, arrowUpIcon, paperclipIcon, undoIcon, downloadIcon, xIcon, moreVerticalIcon, chevronLeftIcon, chevronRightIcon, warningTriangleIcon, pinIcon, arrowDownIcon, cancelIcon, menuIcon, paperPlaneIcon } from '@progress/kendo-svg-icons';
|
|
15
15
|
import * as i1 from '@progress/kendo-angular-l10n';
|
|
16
16
|
import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
|
|
17
17
|
import { validatePackage } from '@progress/kendo-licensing';
|
|
@@ -215,8 +215,8 @@ const packageMetadata = {
|
|
|
215
215
|
productName: 'Kendo UI for Angular',
|
|
216
216
|
productCode: 'KENDOUIANGULAR',
|
|
217
217
|
productCodes: ['KENDOUIANGULAR'],
|
|
218
|
-
publishDate:
|
|
219
|
-
version: '24.0.0-develop.
|
|
218
|
+
publishDate: 1778748700,
|
|
219
|
+
version: '24.0.0-develop.30',
|
|
220
220
|
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
|
|
221
221
|
};
|
|
222
222
|
|
|
@@ -820,7 +820,7 @@ class AIPromptComponent {
|
|
|
820
820
|
/**
|
|
821
821
|
* @hidden
|
|
822
822
|
*/
|
|
823
|
-
fabStopGenerationSVGIcon =
|
|
823
|
+
fabStopGenerationSVGIcon = stopIcon;
|
|
824
824
|
/**
|
|
825
825
|
* @hidden
|
|
826
826
|
*/
|
|
@@ -964,7 +964,7 @@ class AIPromptComponent {
|
|
|
964
964
|
</div>
|
|
965
965
|
</div>
|
|
966
966
|
}
|
|
967
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective$3, selector: "[kendoAIPromptLocalizedMessages]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
967
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective$3, selector: "[kendoAIPromptLocalizedMessages]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: AIPromptToolbarFocusableDirective, selector: "[kendoAIPromptToolbarFocusable]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FloatingActionButtonComponent, selector: "kendo-floatingactionbutton", inputs: ["themeColor", "size", "rounded", "disabled", "align", "offset", "positionMode", "icon", "svgIcon", "iconClass", "buttonClass", "dialClass", "text", "dialItemAnimation", "tabIndex", "dialItems"], outputs: ["blur", "focus", "dialItemClick", "open", "close"] }] });
|
|
968
968
|
}
|
|
969
969
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AIPromptComponent, decorators: [{
|
|
970
970
|
type: Component,
|
|
@@ -1324,17 +1324,17 @@ class AIPromptOutputCardComponent {
|
|
|
1324
1324
|
ngOnInit() {
|
|
1325
1325
|
if (this.promptOutput?.rating === 'positive') {
|
|
1326
1326
|
this.positiveRatingIcon = thumbUpIcon;
|
|
1327
|
-
this.negativeRatingIcon =
|
|
1327
|
+
this.negativeRatingIcon = thumbDownIcon;
|
|
1328
1328
|
}
|
|
1329
1329
|
else if (this.promptOutput?.rating === 'negative') {
|
|
1330
1330
|
this.negativeRatingIcon = thumbDownIcon;
|
|
1331
|
-
this.positiveRatingIcon =
|
|
1331
|
+
this.positiveRatingIcon = thumbUpIcon;
|
|
1332
1332
|
}
|
|
1333
1333
|
}
|
|
1334
1334
|
copyIcon = copyIcon;
|
|
1335
1335
|
retryIcon = arrowRotateCwIcon;
|
|
1336
|
-
positiveRatingIcon =
|
|
1337
|
-
negativeRatingIcon =
|
|
1336
|
+
positiveRatingIcon = thumbUpIcon;
|
|
1337
|
+
negativeRatingIcon = thumbDownIcon;
|
|
1338
1338
|
titleId = `k-output-card-${guid()}`;
|
|
1339
1339
|
messageFor(text) {
|
|
1340
1340
|
return this.localization.get(text);
|
|
@@ -1381,11 +1381,11 @@ class AIPromptOutputCardComponent {
|
|
|
1381
1381
|
this.service.outputRatingChangeEvent.next(eventArgs);
|
|
1382
1382
|
if (ratingType === 'positive') {
|
|
1383
1383
|
this.positiveRatingIcon = thumbUpIcon;
|
|
1384
|
-
this.negativeRatingIcon =
|
|
1384
|
+
this.negativeRatingIcon = thumbDownIcon;
|
|
1385
1385
|
}
|
|
1386
1386
|
else {
|
|
1387
1387
|
this.negativeRatingIcon = thumbDownIcon;
|
|
1388
|
-
this.positiveRatingIcon =
|
|
1388
|
+
this.positiveRatingIcon = thumbUpIcon;
|
|
1389
1389
|
}
|
|
1390
1390
|
}
|
|
1391
1391
|
/**
|
|
@@ -1431,19 +1431,19 @@ class AIPromptOutputCardComponent {
|
|
|
1431
1431
|
<span class="k-spacer"></span>
|
|
1432
1432
|
<button kendoButton
|
|
1433
1433
|
fillMode="flat"
|
|
1434
|
-
icon="thumb-up
|
|
1434
|
+
icon="thumb-up"
|
|
1435
1435
|
[svgIcon]="positiveRatingIcon"
|
|
1436
1436
|
(click)="handleRating('positive')">
|
|
1437
1437
|
</button>
|
|
1438
1438
|
<button kendoButton
|
|
1439
1439
|
fillMode="flat"
|
|
1440
|
-
icon="thumb-down
|
|
1440
|
+
icon="thumb-down"
|
|
1441
1441
|
[svgIcon]="negativeRatingIcon"
|
|
1442
1442
|
(click)="handleRating('negative')">
|
|
1443
1443
|
</button>
|
|
1444
1444
|
}
|
|
1445
1445
|
</div>
|
|
1446
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
1446
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
1447
1447
|
}
|
|
1448
1448
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AIPromptOutputCardComponent, decorators: [{
|
|
1449
1449
|
type: Component,
|
|
@@ -1485,13 +1485,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
1485
1485
|
<span class="k-spacer"></span>
|
|
1486
1486
|
<button kendoButton
|
|
1487
1487
|
fillMode="flat"
|
|
1488
|
-
icon="thumb-up
|
|
1488
|
+
icon="thumb-up"
|
|
1489
1489
|
[svgIcon]="positiveRatingIcon"
|
|
1490
1490
|
(click)="handleRating('positive')">
|
|
1491
1491
|
</button>
|
|
1492
1492
|
<button kendoButton
|
|
1493
1493
|
fillMode="flat"
|
|
1494
|
-
icon="thumb-down
|
|
1494
|
+
icon="thumb-down"
|
|
1495
1495
|
[svgIcon]="negativeRatingIcon"
|
|
1496
1496
|
(click)="handleRating('negative')">
|
|
1497
1497
|
</button>
|
|
@@ -1774,7 +1774,7 @@ class PromptViewComponent extends BaseView {
|
|
|
1774
1774
|
</div>
|
|
1775
1775
|
}
|
|
1776
1776
|
</ng-template>
|
|
1777
|
-
`, isInline: true, dependencies: [{ kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
1777
|
+
`, isInline: true, dependencies: [{ kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }, { kind: "component", type: SpeechToTextButtonComponent, selector: "button[kendoSpeechToTextButton]", inputs: ["disabled", "size", "rounded", "fillMode", "themeColor", "integrationMode", "lang", "continuous", "interimResults", "maxAlternatives"], outputs: ["start", "end", "result", "error", "click"], exportAs: ["kendoSpeechToTextButton"] }] });
|
|
1778
1778
|
}
|
|
1779
1779
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PromptViewComponent, decorators: [{
|
|
1780
1780
|
type: Component,
|
|
@@ -2349,6 +2349,86 @@ const defaultModelFields = {
|
|
|
2349
2349
|
failedField: 'failed'
|
|
2350
2350
|
};
|
|
2351
2351
|
|
|
2352
|
+
/**
|
|
2353
|
+
* @hidden
|
|
2354
|
+
*
|
|
2355
|
+
* Show the scroll-to-bottom button when the user is this many pixels from the bottom.
|
|
2356
|
+
*/
|
|
2357
|
+
const scrollButtonThreshold = 100;
|
|
2358
|
+
/**
|
|
2359
|
+
* @hidden
|
|
2360
|
+
*
|
|
2361
|
+
* Pins a scroll container to a computed target across layout shifts.
|
|
2362
|
+
* Observers extend the idle window until layout has settled; the initial and
|
|
2363
|
+
* final pins bracket the settle window so the viewport lands exactly on target.
|
|
2364
|
+
*/
|
|
2365
|
+
const settleScroll = (zone, el, computeTarget, onComplete, idleMs = 120, timeoutMs = 1000) => {
|
|
2366
|
+
const pin = () => {
|
|
2367
|
+
const t = computeTarget();
|
|
2368
|
+
if (t !== null) {
|
|
2369
|
+
el.scrollTop = t;
|
|
2370
|
+
}
|
|
2371
|
+
};
|
|
2372
|
+
pin();
|
|
2373
|
+
zone.runOutsideAngular(() => {
|
|
2374
|
+
let idleTimer = null;
|
|
2375
|
+
let safetyTimer = null;
|
|
2376
|
+
let mutationObserver = null;
|
|
2377
|
+
let resizeObserver = null;
|
|
2378
|
+
let finished = false;
|
|
2379
|
+
const finish = () => {
|
|
2380
|
+
if (finished) {
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
finished = true;
|
|
2384
|
+
if (mutationObserver) {
|
|
2385
|
+
mutationObserver.disconnect();
|
|
2386
|
+
}
|
|
2387
|
+
if (resizeObserver) {
|
|
2388
|
+
resizeObserver.disconnect();
|
|
2389
|
+
}
|
|
2390
|
+
clearTimeout(idleTimer);
|
|
2391
|
+
clearTimeout(safetyTimer);
|
|
2392
|
+
pin();
|
|
2393
|
+
zone.run(() => {
|
|
2394
|
+
onComplete();
|
|
2395
|
+
requestAnimationFrame(pin);
|
|
2396
|
+
});
|
|
2397
|
+
};
|
|
2398
|
+
const resetIdle = () => {
|
|
2399
|
+
clearTimeout(idleTimer);
|
|
2400
|
+
idleTimer = setTimeout(finish, idleMs);
|
|
2401
|
+
};
|
|
2402
|
+
const onChange = () => {
|
|
2403
|
+
pin();
|
|
2404
|
+
resetIdle();
|
|
2405
|
+
};
|
|
2406
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
2407
|
+
mutationObserver = new MutationObserver(onChange);
|
|
2408
|
+
mutationObserver.observe(el, {
|
|
2409
|
+
childList: true,
|
|
2410
|
+
subtree: true,
|
|
2411
|
+
characterData: true,
|
|
2412
|
+
attributes: true,
|
|
2413
|
+
attributeFilter: ['style', 'class', 'hidden']
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
2417
|
+
resizeObserver = new ResizeObserver(onChange);
|
|
2418
|
+
resizeObserver.observe(el);
|
|
2419
|
+
for (const child of Array.from(el.children)) {
|
|
2420
|
+
resizeObserver.observe(child);
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
if (!mutationObserver && !resizeObserver) {
|
|
2424
|
+
finished = true;
|
|
2425
|
+
zone.run(onComplete);
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
safetyTimer = setTimeout(finish, timeoutMs);
|
|
2429
|
+
resetIdle();
|
|
2430
|
+
});
|
|
2431
|
+
};
|
|
2352
2432
|
/**
|
|
2353
2433
|
* @hidden
|
|
2354
2434
|
*/
|
|
@@ -2396,10 +2476,10 @@ const STB_DEFAULT_SETTINGS$1 = {
|
|
|
2396
2476
|
const SEND_BTN_DEFAULT_SETTINGS = {
|
|
2397
2477
|
rounded: 'full',
|
|
2398
2478
|
size: 'small',
|
|
2399
|
-
icon: 'arrow-up
|
|
2400
|
-
svgIcon:
|
|
2401
|
-
loadingIcon: 'stop
|
|
2402
|
-
loadingSVGIcon:
|
|
2479
|
+
icon: 'arrow-up',
|
|
2480
|
+
svgIcon: arrowUpIcon,
|
|
2481
|
+
loadingIcon: 'stop',
|
|
2482
|
+
loadingSVGIcon: stopIcon,
|
|
2403
2483
|
};
|
|
2404
2484
|
/**
|
|
2405
2485
|
* @hidden
|
|
@@ -2408,8 +2488,8 @@ const FILESELECT_BUTTON_DEFAULT_SETTINGS$1 = {
|
|
|
2408
2488
|
multiple: true,
|
|
2409
2489
|
disabled: false,
|
|
2410
2490
|
fillMode: 'clear',
|
|
2411
|
-
icon: 'paperclip
|
|
2412
|
-
svgIcon:
|
|
2491
|
+
icon: 'paperclip',
|
|
2492
|
+
svgIcon: paperclipIcon,
|
|
2413
2493
|
size: 'small',
|
|
2414
2494
|
rounded: 'full',
|
|
2415
2495
|
};
|
|
@@ -2514,15 +2594,17 @@ const transformActions = (actions) => {
|
|
|
2514
2594
|
* @hidden
|
|
2515
2595
|
*/
|
|
2516
2596
|
class ChatService {
|
|
2597
|
+
zone;
|
|
2517
2598
|
authorId;
|
|
2518
2599
|
messageWidthMode;
|
|
2519
|
-
messageToolbarActions = [];
|
|
2520
2600
|
messageContextMenuActions = [];
|
|
2521
2601
|
calculatedContextMenuActions = [];
|
|
2522
2602
|
fileActions = [];
|
|
2523
2603
|
toggleMessageState = false;
|
|
2604
|
+
layoutChangeInProgress = false;
|
|
2524
2605
|
reply;
|
|
2525
2606
|
messages = [];
|
|
2607
|
+
repliedToMessages = [];
|
|
2526
2608
|
chatElement;
|
|
2527
2609
|
messageElementsMap = new Map();
|
|
2528
2610
|
messagesContextMenu;
|
|
@@ -2540,6 +2622,7 @@ class ChatService {
|
|
|
2540
2622
|
_messageBoxSettings = MESSAGE_BOX_SETTINGS;
|
|
2541
2623
|
_suggestionsLayout = SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS;
|
|
2542
2624
|
_quickActionsLayout = SUGGESTIONS_LAYOUT_DEFAULT_SETTINGS;
|
|
2625
|
+
_messageToolbarActions = [];
|
|
2543
2626
|
_authorMessageSettings;
|
|
2544
2627
|
_receiverMessageSettings;
|
|
2545
2628
|
_allowMessageCollapse;
|
|
@@ -2557,6 +2640,7 @@ class ChatService {
|
|
|
2557
2640
|
authorMessageSettingsChange: new Subject(),
|
|
2558
2641
|
receiverMessageSettingsChange: new Subject(),
|
|
2559
2642
|
allowMessageCollapseChange: new Subject(),
|
|
2643
|
+
messageToolbarActionsChange: new Subject(),
|
|
2560
2644
|
};
|
|
2561
2645
|
toolbarAction$ = this.subjects.toolbarAction.asObservable();
|
|
2562
2646
|
contextMenuAction$ = this.subjects.contextMenuAction.asObservable();
|
|
@@ -2571,6 +2655,10 @@ class ChatService {
|
|
|
2571
2655
|
authorMessageSettingsChange$ = this.subjects.authorMessageSettingsChange.asObservable();
|
|
2572
2656
|
receiverMessageSettingsChange$ = this.subjects.receiverMessageSettingsChange.asObservable();
|
|
2573
2657
|
allowMessageCollapseChange$ = this.subjects.allowMessageCollapseChange.asObservable();
|
|
2658
|
+
messageToolbarActionsChange$ = this.subjects.messageToolbarActionsChange.asObservable();
|
|
2659
|
+
constructor(zone) {
|
|
2660
|
+
this.zone = zone;
|
|
2661
|
+
}
|
|
2574
2662
|
set authorMessageSettings(settings) {
|
|
2575
2663
|
const previousSettings = this._authorMessageSettings;
|
|
2576
2664
|
if (JSON.stringify(previousSettings) !== JSON.stringify(settings)) {
|
|
@@ -2629,6 +2717,13 @@ class ChatService {
|
|
|
2629
2717
|
get quickActionsLayout() {
|
|
2630
2718
|
return this._quickActionsLayout;
|
|
2631
2719
|
}
|
|
2720
|
+
set messageToolbarActions(value) {
|
|
2721
|
+
this._messageToolbarActions = value;
|
|
2722
|
+
this.emit('messageToolbarActionsChange', this._messageToolbarActions);
|
|
2723
|
+
}
|
|
2724
|
+
get messageToolbarActions() {
|
|
2725
|
+
return this._messageToolbarActions;
|
|
2726
|
+
}
|
|
2632
2727
|
set allowMessageCollapse(value) {
|
|
2633
2728
|
const previousValue = this._allowMessageCollapse;
|
|
2634
2729
|
if (previousValue !== value) {
|
|
@@ -2651,7 +2746,8 @@ class ChatService {
|
|
|
2651
2746
|
(this.subjects[subjectKey]).next(value);
|
|
2652
2747
|
}
|
|
2653
2748
|
getMessageById(id) {
|
|
2654
|
-
return this.messages.find(message => message.id === id)
|
|
2749
|
+
return this.messages.find(message => message.id === id)
|
|
2750
|
+
?? this.repliedToMessages.find(message => message.id === id);
|
|
2655
2751
|
}
|
|
2656
2752
|
registerMessageElement(messageId, elementRef) {
|
|
2657
2753
|
this.messageElementsMap.set(messageId, elementRef);
|
|
@@ -2662,26 +2758,25 @@ class ChatService {
|
|
|
2662
2758
|
this.reply = null;
|
|
2663
2759
|
}
|
|
2664
2760
|
}
|
|
2665
|
-
scrollToMessage(messageId) {
|
|
2666
|
-
|
|
2667
|
-
if (!elementRef?.nativeElement) {
|
|
2761
|
+
scrollToMessage(messageId, behavior = 'smooth') {
|
|
2762
|
+
if (!isDocumentAvailable()) {
|
|
2668
2763
|
return;
|
|
2669
2764
|
}
|
|
2670
|
-
const scrollContainer = this.
|
|
2765
|
+
const scrollContainer = this.getScrollContainer();
|
|
2671
2766
|
if (!scrollContainer) {
|
|
2672
2767
|
return;
|
|
2673
2768
|
}
|
|
2674
|
-
const
|
|
2675
|
-
const
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
}
|
|
2769
|
+
const computeTarget = () => this.computeScrollTarget(messageId);
|
|
2770
|
+
const scrollTop = computeTarget();
|
|
2771
|
+
if (scrollTop === null) {
|
|
2772
|
+
return;
|
|
2773
|
+
}
|
|
2774
|
+
if (behavior === 'auto') {
|
|
2775
|
+
settleScroll(this.zone, scrollContainer, computeTarget, () => { });
|
|
2776
|
+
}
|
|
2777
|
+
else {
|
|
2778
|
+
scrollContainer.scrollTo({ top: scrollTop, behavior });
|
|
2779
|
+
}
|
|
2685
2780
|
}
|
|
2686
2781
|
focusActiveMessageElement() {
|
|
2687
2782
|
if (this.activeMessageElement) {
|
|
@@ -2691,6 +2786,25 @@ class ChatService {
|
|
|
2691
2786
|
isOwnMessage(message) {
|
|
2692
2787
|
return this.authorId === message.author.id;
|
|
2693
2788
|
}
|
|
2789
|
+
getScrollContainer() {
|
|
2790
|
+
return this.chatElement?.element?.nativeElement ?? null;
|
|
2791
|
+
}
|
|
2792
|
+
computeScrollTarget(messageId) {
|
|
2793
|
+
const elementRef = this.messageElementsMap.get(messageId);
|
|
2794
|
+
if (!elementRef?.nativeElement) {
|
|
2795
|
+
return null;
|
|
2796
|
+
}
|
|
2797
|
+
const scrollContainer = this.getScrollContainer();
|
|
2798
|
+
if (!scrollContainer) {
|
|
2799
|
+
return null;
|
|
2800
|
+
}
|
|
2801
|
+
const targetElement = elementRef.nativeElement;
|
|
2802
|
+
const pinnedElement = scrollContainer.querySelector('.k-message-pinned');
|
|
2803
|
+
const pinnedHeight = pinnedElement?.offsetHeight || 0;
|
|
2804
|
+
const containerRect = scrollContainer.getBoundingClientRect();
|
|
2805
|
+
const targetRect = targetElement.getBoundingClientRect();
|
|
2806
|
+
return targetRect.top - containerRect.top + scrollContainer.scrollTop - pinnedHeight;
|
|
2807
|
+
}
|
|
2694
2808
|
updateComponentSettings(property, settings, defaultSettings) {
|
|
2695
2809
|
if (settings === true) {
|
|
2696
2810
|
this[property] = defaultSettings;
|
|
@@ -2702,17 +2816,17 @@ class ChatService {
|
|
|
2702
2816
|
this[property] = { ...defaultSettings, ...settings };
|
|
2703
2817
|
}
|
|
2704
2818
|
}
|
|
2705
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2819
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2706
2820
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatService });
|
|
2707
2821
|
}
|
|
2708
2822
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatService, decorators: [{
|
|
2709
2823
|
type: Injectable
|
|
2710
|
-
}] });
|
|
2824
|
+
}], ctorParameters: () => [{ type: i0.NgZone }] });
|
|
2711
2825
|
|
|
2712
2826
|
// Consider scroll to be at the bottom when within this number of pixels from the container height.
|
|
2713
2827
|
const maxDelta = 2;
|
|
2714
|
-
//
|
|
2715
|
-
const
|
|
2828
|
+
// Edge detection threshold for endless scroll — fire loadMore when within this many pixels.
|
|
2829
|
+
const edgeThreshold = 100;
|
|
2716
2830
|
/**
|
|
2717
2831
|
* @hidden
|
|
2718
2832
|
*/
|
|
@@ -2722,13 +2836,53 @@ class ScrollAnchorDirective {
|
|
|
2722
2836
|
renderer;
|
|
2723
2837
|
cdr;
|
|
2724
2838
|
autoScroll = true;
|
|
2839
|
+
autoScrollThreshold = '20%';
|
|
2840
|
+
set endlessMode(value) {
|
|
2841
|
+
const changed = this._endlessMode !== value;
|
|
2842
|
+
this._endlessMode = value;
|
|
2843
|
+
this._nearTopLocked = false;
|
|
2844
|
+
this._nearBottomLocked = false;
|
|
2845
|
+
this.scrolling = false;
|
|
2846
|
+
if (changed && !value && this._initialScrollDone && isDocumentAvailable()) {
|
|
2847
|
+
this.element.nativeElement.scrollTo({ top: 0, behavior: 'auto' });
|
|
2848
|
+
this._subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
2849
|
+
this.performScroll('smooth');
|
|
2850
|
+
}));
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
get endlessMode() {
|
|
2854
|
+
return this._endlessMode;
|
|
2855
|
+
}
|
|
2856
|
+
rangeIsAtEnd = true;
|
|
2725
2857
|
autoScrollChange = new EventEmitter();
|
|
2858
|
+
nearTop = new EventEmitter();
|
|
2859
|
+
nearBottom = new EventEmitter();
|
|
2726
2860
|
overflowAnchor = 'none';
|
|
2861
|
+
get scrollBehaviorStyle() {
|
|
2862
|
+
return this._endlessMode ? 'auto' : null;
|
|
2863
|
+
}
|
|
2727
2864
|
showScrollToBottomButton = false;
|
|
2728
2865
|
showMessageBoxSeparator = false;
|
|
2729
2866
|
scrolling = false;
|
|
2730
2867
|
unsubscribe;
|
|
2731
2868
|
scrollUpdate = null;
|
|
2869
|
+
_previousScrollHeight = 0;
|
|
2870
|
+
_previousScrollTop = 0;
|
|
2871
|
+
_pendingScrollPreservation = false;
|
|
2872
|
+
_endlessMode = false;
|
|
2873
|
+
_nearTopLocked = false;
|
|
2874
|
+
_nearBottomLocked = false;
|
|
2875
|
+
_scrollingToMessage = false;
|
|
2876
|
+
_initialScrollDone = false;
|
|
2877
|
+
_subs = new Subscription();
|
|
2878
|
+
// Need to ensure that the scroll follows a new streaming message
|
|
2879
|
+
// until the scroll threshold is reached.
|
|
2880
|
+
_streamingFollow = false;
|
|
2881
|
+
_thresholdScrollCap = null;
|
|
2882
|
+
_streamingPrevScrollTop = 0;
|
|
2883
|
+
_streamingPrevHeight = 0;
|
|
2884
|
+
_streamingPrevMsgCount = 0;
|
|
2885
|
+
_mutationObserver = null;
|
|
2732
2886
|
constructor(element, zone, renderer, cdr) {
|
|
2733
2887
|
this.element = element;
|
|
2734
2888
|
this.zone = zone;
|
|
@@ -2736,15 +2890,54 @@ class ScrollAnchorDirective {
|
|
|
2736
2890
|
this.cdr = cdr;
|
|
2737
2891
|
}
|
|
2738
2892
|
ngOnInit() {
|
|
2893
|
+
if (!isDocumentAvailable()) {
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2739
2896
|
this.zone.runOutsideAngular(() => {
|
|
2740
|
-
|
|
2897
|
+
const el = this.element.nativeElement;
|
|
2898
|
+
this.unsubscribe = this.renderer.listen(el, 'scroll', () => {
|
|
2899
|
+
this.detectStreamingScrollUp();
|
|
2900
|
+
this.setupScrollUpdate();
|
|
2901
|
+
}, { passive: true });
|
|
2902
|
+
this._mutationObserver = new MutationObserver(() => {
|
|
2903
|
+
if (!this._streamingFollow) {
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2906
|
+
const currentMsgCount = el.querySelectorAll('.k-message').length;
|
|
2907
|
+
const currentHeight = el.scrollHeight;
|
|
2908
|
+
if (currentMsgCount === this._streamingPrevMsgCount && currentHeight > this._streamingPrevHeight) {
|
|
2909
|
+
const bottom = currentHeight - el.clientHeight;
|
|
2910
|
+
const cap = this._thresholdScrollCap;
|
|
2911
|
+
const target = cap !== null ? Math.min(bottom, cap) : bottom;
|
|
2912
|
+
if (target > el.scrollTop) {
|
|
2913
|
+
el.scrollTop = target;
|
|
2914
|
+
}
|
|
2915
|
+
this._streamingPrevScrollTop = el.scrollTop;
|
|
2916
|
+
this.updateScrollToBottomButton(el);
|
|
2917
|
+
}
|
|
2918
|
+
this._streamingPrevMsgCount = currentMsgCount;
|
|
2919
|
+
this._streamingPrevHeight = currentHeight;
|
|
2920
|
+
});
|
|
2921
|
+
this._mutationObserver.observe(el, {
|
|
2922
|
+
childList: true,
|
|
2923
|
+
subtree: true,
|
|
2924
|
+
characterData: true,
|
|
2925
|
+
});
|
|
2741
2926
|
});
|
|
2742
2927
|
}
|
|
2743
2928
|
ngAfterViewInit() {
|
|
2744
|
-
this.
|
|
2745
|
-
|
|
2929
|
+
this._subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
2930
|
+
if (this.autoScroll) {
|
|
2931
|
+
if (this._endlessMode) {
|
|
2932
|
+
this.scrollToBottomWithSettle();
|
|
2933
|
+
}
|
|
2934
|
+
else {
|
|
2935
|
+
this.performScroll('smooth');
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2746
2938
|
this.calculateMessageBoxSeparator();
|
|
2747
|
-
|
|
2939
|
+
this._initialScrollDone = true;
|
|
2940
|
+
}));
|
|
2748
2941
|
}
|
|
2749
2942
|
ngOnDestroy() {
|
|
2750
2943
|
if (this.unsubscribe) {
|
|
@@ -2753,8 +2946,16 @@ class ScrollAnchorDirective {
|
|
|
2753
2946
|
if (this.scrollUpdate !== null) {
|
|
2754
2947
|
cancelAnimationFrame(this.scrollUpdate);
|
|
2755
2948
|
}
|
|
2949
|
+
if (this._mutationObserver) {
|
|
2950
|
+
this._mutationObserver.disconnect();
|
|
2951
|
+
this._mutationObserver = null;
|
|
2952
|
+
}
|
|
2953
|
+
this._subs.unsubscribe();
|
|
2756
2954
|
}
|
|
2757
2955
|
onScroll() {
|
|
2956
|
+
if (!isDocumentAvailable() || this._scrollingToMessage) {
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2758
2959
|
const el = this.element.nativeElement;
|
|
2759
2960
|
const scrollPosition = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
2760
2961
|
const atBottom = scrollPosition < maxDelta;
|
|
@@ -2764,7 +2965,8 @@ class ScrollAnchorDirective {
|
|
|
2764
2965
|
}
|
|
2765
2966
|
return;
|
|
2766
2967
|
}
|
|
2767
|
-
const showScrollButton = scrollPosition > scrollButtonThreshold
|
|
2968
|
+
const showScrollButton = scrollPosition > scrollButtonThreshold
|
|
2969
|
+
|| (this.endlessMode && !this.rangeIsAtEnd);
|
|
2768
2970
|
const autoScrollChanged = this.autoScroll !== atBottom;
|
|
2769
2971
|
const buttonChanged = this.showScrollToBottomButton !== showScrollButton;
|
|
2770
2972
|
if (autoScrollChanged || buttonChanged) {
|
|
@@ -2779,8 +2981,30 @@ class ScrollAnchorDirective {
|
|
|
2779
2981
|
}
|
|
2780
2982
|
});
|
|
2781
2983
|
}
|
|
2984
|
+
if (this.endlessMode) {
|
|
2985
|
+
const nearTopEdge = el.scrollTop < edgeThreshold;
|
|
2986
|
+
const nearBottomEdge = !this.rangeIsAtEnd && scrollPosition < edgeThreshold;
|
|
2987
|
+
if (!nearTopEdge) {
|
|
2988
|
+
this._nearTopLocked = false;
|
|
2989
|
+
}
|
|
2990
|
+
if (!nearBottomEdge) {
|
|
2991
|
+
this._nearBottomLocked = false;
|
|
2992
|
+
}
|
|
2993
|
+
if (nearTopEdge && !this._nearTopLocked) {
|
|
2994
|
+
this._nearTopLocked = true;
|
|
2995
|
+
this.zone.run(() => this.nearTop.emit());
|
|
2996
|
+
}
|
|
2997
|
+
if (nearBottomEdge && !this._nearBottomLocked) {
|
|
2998
|
+
this._nearBottomLocked = true;
|
|
2999
|
+
this.zone.run(() => this.nearBottom.emit());
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
2782
3002
|
}
|
|
2783
3003
|
autoScrollToBottom() {
|
|
3004
|
+
if (this._streamingFollow) {
|
|
3005
|
+
this.followStreamingContent();
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
2784
3008
|
if (!this.autoScroll) {
|
|
2785
3009
|
return;
|
|
2786
3010
|
}
|
|
@@ -2789,9 +3013,80 @@ class ScrollAnchorDirective {
|
|
|
2789
3013
|
scrollToBottom() {
|
|
2790
3014
|
this.autoScroll = true;
|
|
2791
3015
|
this.showScrollToBottomButton = false;
|
|
3016
|
+
this._streamingFollow = false;
|
|
3017
|
+
this._thresholdScrollCap = null;
|
|
2792
3018
|
this.performScroll();
|
|
2793
3019
|
}
|
|
3020
|
+
scrollToBottomWithSettle(onComplete) {
|
|
3021
|
+
if (!isDocumentAvailable()) {
|
|
3022
|
+
onComplete?.();
|
|
3023
|
+
return;
|
|
3024
|
+
}
|
|
3025
|
+
const el = this.element.nativeElement;
|
|
3026
|
+
this._scrollingToMessage = true;
|
|
3027
|
+
this._streamingFollow = false;
|
|
3028
|
+
this._thresholdScrollCap = null;
|
|
3029
|
+
settleScroll(this.zone, el, () => el.scrollHeight - el.clientHeight, () => {
|
|
3030
|
+
this.autoScroll = true;
|
|
3031
|
+
this.showScrollToBottomButton = false;
|
|
3032
|
+
this.scrolling = false;
|
|
3033
|
+
this._scrollingToMessage = false;
|
|
3034
|
+
this.cdr.markForCheck();
|
|
3035
|
+
onComplete?.();
|
|
3036
|
+
});
|
|
3037
|
+
}
|
|
3038
|
+
scrollWithThreshold(messageEl) {
|
|
3039
|
+
if (!isDocumentAvailable() || !messageEl) {
|
|
3040
|
+
this.performScroll();
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
const container = this.element.nativeElement;
|
|
3044
|
+
const pinnedHeight = this.getPinnedBarHeight();
|
|
3045
|
+
const thresholdPx = Math.max(0, this.parseThreshold(pinnedHeight));
|
|
3046
|
+
const containerRect = container.getBoundingClientRect();
|
|
3047
|
+
const messageRect = messageEl.getBoundingClientRect();
|
|
3048
|
+
const msgTopInContent = messageRect.top - containerRect.top + container.scrollTop;
|
|
3049
|
+
const targetScrollTop = Math.max(0, msgTopInContent - thresholdPx - pinnedHeight);
|
|
3050
|
+
const bottomScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
3051
|
+
const finalScrollTop = Math.min(targetScrollTop, bottomScrollTop);
|
|
3052
|
+
if (finalScrollTop > container.scrollTop) {
|
|
3053
|
+
container.scrollTo({ top: finalScrollTop, behavior: this._endlessMode ? 'auto' : 'smooth' });
|
|
3054
|
+
}
|
|
3055
|
+
this._thresholdScrollCap = targetScrollTop;
|
|
3056
|
+
this._streamingFollow = true;
|
|
3057
|
+
this._streamingPrevScrollTop = container.scrollTop;
|
|
3058
|
+
this._streamingPrevHeight = container.scrollHeight;
|
|
3059
|
+
this._streamingPrevMsgCount = container.querySelectorAll('.k-message').length;
|
|
3060
|
+
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
|
|
3061
|
+
this.showScrollToBottomButton = distanceFromBottom > scrollButtonThreshold;
|
|
3062
|
+
this.cdr.markForCheck();
|
|
3063
|
+
}
|
|
3064
|
+
recordScrollHeight() {
|
|
3065
|
+
if (!isDocumentAvailable()) {
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
const el = this.element.nativeElement;
|
|
3069
|
+
this._previousScrollHeight = el.scrollHeight;
|
|
3070
|
+
this._previousScrollTop = el.scrollTop;
|
|
3071
|
+
this._pendingScrollPreservation = true;
|
|
3072
|
+
this.cdr.markForCheck();
|
|
3073
|
+
}
|
|
3074
|
+
preserveScrollPosition() {
|
|
3075
|
+
if (!this._pendingScrollPreservation || !isDocumentAvailable()) {
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
const el = this.element.nativeElement;
|
|
3079
|
+
const delta = el.scrollHeight - this._previousScrollHeight;
|
|
3080
|
+
if (delta > 0) {
|
|
3081
|
+
el.scrollTop = this._previousScrollTop + delta;
|
|
3082
|
+
}
|
|
3083
|
+
this._pendingScrollPreservation = false;
|
|
3084
|
+
this.cdr.markForCheck();
|
|
3085
|
+
}
|
|
2794
3086
|
calculateMessageBoxSeparator() {
|
|
3087
|
+
if (!isDocumentAvailable()) {
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
2795
3090
|
const el = this.element.nativeElement;
|
|
2796
3091
|
const shouldShow = el.scrollHeight > el.clientHeight;
|
|
2797
3092
|
if (this.showMessageBoxSeparator !== shouldShow) {
|
|
@@ -2799,6 +3094,90 @@ class ScrollAnchorDirective {
|
|
|
2799
3094
|
this.cdr.markForCheck();
|
|
2800
3095
|
}
|
|
2801
3096
|
}
|
|
3097
|
+
getDistanceFromBottom() {
|
|
3098
|
+
if (!isDocumentAvailable()) {
|
|
3099
|
+
return 0;
|
|
3100
|
+
}
|
|
3101
|
+
const el = this.element.nativeElement;
|
|
3102
|
+
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
3103
|
+
}
|
|
3104
|
+
setAriaLive(value) {
|
|
3105
|
+
if (!isDocumentAvailable()) {
|
|
3106
|
+
return;
|
|
3107
|
+
}
|
|
3108
|
+
this.renderer.setAttribute(this.element.nativeElement, 'aria-live', value);
|
|
3109
|
+
}
|
|
3110
|
+
lockForMessageScroll() {
|
|
3111
|
+
this._scrollingToMessage = true;
|
|
3112
|
+
}
|
|
3113
|
+
unlockForMessageScroll() {
|
|
3114
|
+
this._scrollingToMessage = false;
|
|
3115
|
+
this.setupScrollUpdate();
|
|
3116
|
+
}
|
|
3117
|
+
getAutoScrollThresholdPx() {
|
|
3118
|
+
return Math.max(0, this.parseThreshold(this.getPinnedBarHeight()));
|
|
3119
|
+
}
|
|
3120
|
+
get isFollowingThreshold() {
|
|
3121
|
+
return this._streamingFollow;
|
|
3122
|
+
}
|
|
3123
|
+
followStreamingContent() {
|
|
3124
|
+
if (!isDocumentAvailable()) {
|
|
3125
|
+
return;
|
|
3126
|
+
}
|
|
3127
|
+
const el = this.element.nativeElement;
|
|
3128
|
+
const bottom = el.scrollHeight - el.clientHeight;
|
|
3129
|
+
const cap = this._thresholdScrollCap;
|
|
3130
|
+
const target = cap !== null ? Math.min(bottom, cap) : bottom;
|
|
3131
|
+
if (target > el.scrollTop) {
|
|
3132
|
+
el.scrollTop = target;
|
|
3133
|
+
this._streamingPrevScrollTop = el.scrollTop;
|
|
3134
|
+
}
|
|
3135
|
+
this.updateScrollToBottomButton(el);
|
|
3136
|
+
}
|
|
3137
|
+
updateScrollToBottomButton(el) {
|
|
3138
|
+
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
3139
|
+
const shouldShow = distance > scrollButtonThreshold
|
|
3140
|
+
|| (this.endlessMode && !this.rangeIsAtEnd);
|
|
3141
|
+
if (this.showScrollToBottomButton !== shouldShow) {
|
|
3142
|
+
this.zone.run(() => {
|
|
3143
|
+
this.showScrollToBottomButton = shouldShow;
|
|
3144
|
+
this.cdr.markForCheck();
|
|
3145
|
+
});
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
detectStreamingScrollUp() {
|
|
3149
|
+
if (!this._streamingFollow) {
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
const st = this.element.nativeElement.scrollTop;
|
|
3153
|
+
if (st < this._streamingPrevScrollTop) {
|
|
3154
|
+
this._streamingFollow = false;
|
|
3155
|
+
this._thresholdScrollCap = null;
|
|
3156
|
+
}
|
|
3157
|
+
this._streamingPrevScrollTop = st;
|
|
3158
|
+
}
|
|
3159
|
+
parseThreshold(pinnedHeight = 0) {
|
|
3160
|
+
const threshold = this.autoScrollThreshold;
|
|
3161
|
+
if (typeof threshold === 'number') {
|
|
3162
|
+
return threshold;
|
|
3163
|
+
}
|
|
3164
|
+
if (typeof threshold === 'string') {
|
|
3165
|
+
if (threshold.endsWith('%')) {
|
|
3166
|
+
const percent = parseFloat(threshold) / 100;
|
|
3167
|
+
const visibleHeight = this.element.nativeElement.clientHeight - pinnedHeight;
|
|
3168
|
+
return visibleHeight * percent;
|
|
3169
|
+
}
|
|
3170
|
+
const parsed = parseFloat(threshold);
|
|
3171
|
+
if (!isNaN(parsed)) {
|
|
3172
|
+
return parsed;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
return 0;
|
|
3176
|
+
}
|
|
3177
|
+
getPinnedBarHeight() {
|
|
3178
|
+
const pinned = this.element.nativeElement.querySelector('.k-message-pinned');
|
|
3179
|
+
return pinned ? pinned.offsetHeight : 0;
|
|
3180
|
+
}
|
|
2802
3181
|
setupScrollUpdate() {
|
|
2803
3182
|
if (this.scrollUpdate !== null) {
|
|
2804
3183
|
return;
|
|
@@ -2808,13 +3187,20 @@ class ScrollAnchorDirective {
|
|
|
2808
3187
|
this.onScroll();
|
|
2809
3188
|
});
|
|
2810
3189
|
}
|
|
2811
|
-
performScroll() {
|
|
3190
|
+
performScroll(behavior = 'auto') {
|
|
3191
|
+
if (!isDocumentAvailable()) {
|
|
3192
|
+
return;
|
|
3193
|
+
}
|
|
2812
3194
|
const el = this.element.nativeElement;
|
|
2813
|
-
|
|
3195
|
+
const target = el.scrollHeight - el.clientHeight;
|
|
3196
|
+
if (Math.abs(el.scrollTop - target) < maxDelta) {
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
3199
|
+
el.scrollTo({ top: target, behavior });
|
|
2814
3200
|
this.scrolling = true;
|
|
2815
3201
|
}
|
|
2816
3202
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ScrollAnchorDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2817
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.20", type: ScrollAnchorDirective, isStandalone: true, selector: "[kendoChatScrollAnchor]", inputs: { autoScroll: "autoScroll" }, outputs: { autoScrollChange: "autoScrollChange" }, host: { properties: { "style.overflow-anchor": "this.overflowAnchor" } }, exportAs: ["scrollAnchor"], ngImport: i0 });
|
|
3203
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.20", type: ScrollAnchorDirective, isStandalone: true, selector: "[kendoChatScrollAnchor]", inputs: { autoScroll: "autoScroll", autoScrollThreshold: "autoScrollThreshold", endlessMode: "endlessMode", rangeIsAtEnd: "rangeIsAtEnd" }, outputs: { autoScrollChange: "autoScrollChange", nearTop: "nearTop", nearBottom: "nearBottom" }, host: { properties: { "style.overflow-anchor": "this.overflowAnchor", "style.scroll-behavior": "this.scrollBehaviorStyle" } }, exportAs: ["scrollAnchor"], ngImport: i0 });
|
|
2818
3204
|
}
|
|
2819
3205
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ScrollAnchorDirective, decorators: [{
|
|
2820
3206
|
type: Directive,
|
|
@@ -2825,11 +3211,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
2825
3211
|
}]
|
|
2826
3212
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }], propDecorators: { autoScroll: [{
|
|
2827
3213
|
type: Input
|
|
3214
|
+
}], autoScrollThreshold: [{
|
|
3215
|
+
type: Input
|
|
3216
|
+
}], endlessMode: [{
|
|
3217
|
+
type: Input
|
|
3218
|
+
}], rangeIsAtEnd: [{
|
|
3219
|
+
type: Input
|
|
2828
3220
|
}], autoScrollChange: [{
|
|
2829
3221
|
type: Output
|
|
3222
|
+
}], nearTop: [{
|
|
3223
|
+
type: Output
|
|
3224
|
+
}], nearBottom: [{
|
|
3225
|
+
type: Output
|
|
2830
3226
|
}], overflowAnchor: [{
|
|
2831
3227
|
type: HostBinding,
|
|
2832
3228
|
args: ['style.overflow-anchor']
|
|
3229
|
+
}], scrollBehaviorStyle: [{
|
|
3230
|
+
type: HostBinding,
|
|
3231
|
+
args: ['style.scroll-behavior']
|
|
2833
3232
|
}] } });
|
|
2834
3233
|
|
|
2835
3234
|
const DEFAULT_SCROLL_BEHAVIOR = 'smooth';
|
|
@@ -2933,6 +3332,93 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
2933
3332
|
type: Injectable
|
|
2934
3333
|
}], ctorParameters: () => [{ type: i0.NgZone }, { type: i1.LocalizationService }] });
|
|
2935
3334
|
|
|
3335
|
+
/**
|
|
3336
|
+
* @hidden
|
|
3337
|
+
*/
|
|
3338
|
+
class EndlessScrollState {
|
|
3339
|
+
startIndex = 0;
|
|
3340
|
+
endIndex = 0;
|
|
3341
|
+
isLoading = false;
|
|
3342
|
+
get isAtStart() {
|
|
3343
|
+
return this.startIndex === 0;
|
|
3344
|
+
}
|
|
3345
|
+
get isAtEnd() {
|
|
3346
|
+
return this.endIndex >= this._total;
|
|
3347
|
+
}
|
|
3348
|
+
_total = 0;
|
|
3349
|
+
_pageSize = 50;
|
|
3350
|
+
get pageSize() {
|
|
3351
|
+
return this._pageSize;
|
|
3352
|
+
}
|
|
3353
|
+
init(total, pageSize) {
|
|
3354
|
+
this._total = total;
|
|
3355
|
+
this._pageSize = pageSize;
|
|
3356
|
+
return this.jumpToEnd();
|
|
3357
|
+
}
|
|
3358
|
+
extendUp() {
|
|
3359
|
+
if (this.isAtStart || this.isLoading) {
|
|
3360
|
+
return null;
|
|
3361
|
+
}
|
|
3362
|
+
const newStart = Math.max(0, this.startIndex - this._pageSize);
|
|
3363
|
+
if (newStart === this.startIndex) {
|
|
3364
|
+
return null;
|
|
3365
|
+
}
|
|
3366
|
+
this.startIndex = newStart;
|
|
3367
|
+
return { start: this.startIndex, end: this.endIndex };
|
|
3368
|
+
}
|
|
3369
|
+
extendDown() {
|
|
3370
|
+
if (this.isAtEnd || this.isLoading) {
|
|
3371
|
+
return null;
|
|
3372
|
+
}
|
|
3373
|
+
const newEnd = Math.min(this._total, this.endIndex + this._pageSize);
|
|
3374
|
+
if (newEnd === this.endIndex) {
|
|
3375
|
+
return null;
|
|
3376
|
+
}
|
|
3377
|
+
this.endIndex = newEnd;
|
|
3378
|
+
return { start: this.startIndex, end: this.endIndex };
|
|
3379
|
+
}
|
|
3380
|
+
jumpTo(targetIndex) {
|
|
3381
|
+
const half = Math.floor(this._pageSize / 2);
|
|
3382
|
+
let start = targetIndex - half;
|
|
3383
|
+
let end = start + this._pageSize;
|
|
3384
|
+
if (start < 0) {
|
|
3385
|
+
start = 0;
|
|
3386
|
+
end = Math.min(this._pageSize, this._total);
|
|
3387
|
+
}
|
|
3388
|
+
if (end > this._total) {
|
|
3389
|
+
end = this._total;
|
|
3390
|
+
start = Math.max(0, end - this._pageSize);
|
|
3391
|
+
}
|
|
3392
|
+
this.startIndex = start;
|
|
3393
|
+
this.endIndex = end;
|
|
3394
|
+
return { start, end };
|
|
3395
|
+
}
|
|
3396
|
+
jumpToEnd() {
|
|
3397
|
+
const start = Math.max(0, this._total - this._pageSize);
|
|
3398
|
+
const end = this._total;
|
|
3399
|
+
this.startIndex = start;
|
|
3400
|
+
this.endIndex = end;
|
|
3401
|
+
return { start, end };
|
|
3402
|
+
}
|
|
3403
|
+
updateTotal(total) {
|
|
3404
|
+
this._total = total;
|
|
3405
|
+
}
|
|
3406
|
+
reset() {
|
|
3407
|
+
this.startIndex = 0;
|
|
3408
|
+
this.endIndex = 0;
|
|
3409
|
+
this.isLoading = false;
|
|
3410
|
+
this._total = 0;
|
|
3411
|
+
}
|
|
3412
|
+
contains(index) {
|
|
3413
|
+
return index >= this.startIndex && index < this.endIndex;
|
|
3414
|
+
}
|
|
3415
|
+
syncFromInputs(start, end, total) {
|
|
3416
|
+
this.startIndex = start;
|
|
3417
|
+
this.endIndex = end;
|
|
3418
|
+
this._total = total;
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
|
|
2936
3422
|
/**
|
|
2937
3423
|
* @hidden
|
|
2938
3424
|
*/
|
|
@@ -3113,7 +3599,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
3113
3599
|
* ```html
|
|
3114
3600
|
* <kendo-promptbox>
|
|
3115
3601
|
* <kendo-promptbox-end-affix>
|
|
3116
|
-
* <button kendoButton
|
|
3602
|
+
* <button kendoButton fillMode="clear" [svgIcon]="imageIcon"></button>
|
|
3117
3603
|
* </kendo-promptbox-end-affix>
|
|
3118
3604
|
* </kendo-promptbox>
|
|
3119
3605
|
* ```
|
|
@@ -3146,7 +3632,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
3146
3632
|
* ```html
|
|
3147
3633
|
* <kendo-promptbox>
|
|
3148
3634
|
* <kendo-promptbox-start-affix>
|
|
3149
|
-
* <button kendoButton
|
|
3635
|
+
* <button kendoButton fillMode="clear" [svgIcon]="imageIcon"></button>
|
|
3150
3636
|
* </kendo-promptbox-start-affix>
|
|
3151
3637
|
* </kendo-promptbox>
|
|
3152
3638
|
* ```
|
|
@@ -3179,7 +3665,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
3179
3665
|
* ```html
|
|
3180
3666
|
* <kendo-promptbox>
|
|
3181
3667
|
* <kendo-promptbox-top-affix>
|
|
3182
|
-
* <button kendoButton
|
|
3668
|
+
* <button kendoButton fillMode="clear" [svgIcon]="imageIcon"></button>
|
|
3183
3669
|
* </kendo-promptbox-top-affix>
|
|
3184
3670
|
* </kendo-promptbox>
|
|
3185
3671
|
* ```
|
|
@@ -3325,10 +3811,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
3325
3811
|
const ACTION_BUTTON_DEFAULT_SETTINGS = {
|
|
3326
3812
|
rounded: 'full',
|
|
3327
3813
|
size: 'small',
|
|
3328
|
-
icon: 'arrow-up
|
|
3329
|
-
svgIcon:
|
|
3330
|
-
loadingIcon: 'stop
|
|
3331
|
-
loadingSVGIcon:
|
|
3814
|
+
icon: 'arrow-up',
|
|
3815
|
+
svgIcon: arrowUpIcon,
|
|
3816
|
+
loadingIcon: 'stop',
|
|
3817
|
+
loadingSVGIcon: stopIcon,
|
|
3332
3818
|
};
|
|
3333
3819
|
/**
|
|
3334
3820
|
* @hidden
|
|
@@ -3352,8 +3838,8 @@ const FILESELECT_BUTTON_DEFAULT_SETTINGS = {
|
|
|
3352
3838
|
fillMode: 'flat',
|
|
3353
3839
|
size: 'small',
|
|
3354
3840
|
rounded: 'full',
|
|
3355
|
-
icon: 'paperclip
|
|
3356
|
-
svgIcon:
|
|
3841
|
+
icon: 'paperclip',
|
|
3842
|
+
svgIcon: paperclipIcon,
|
|
3357
3843
|
multiple: true,
|
|
3358
3844
|
restrictions: null,
|
|
3359
3845
|
accept: null
|
|
@@ -3507,15 +3993,15 @@ class PromptBoxActionButtonComponent extends PromptBoxBaseTool {
|
|
|
3507
3993
|
/**
|
|
3508
3994
|
* Sets the icon to be displayed when the **Action** button is in loading state.
|
|
3509
3995
|
*
|
|
3510
|
-
* @default 'stop
|
|
3996
|
+
* @default 'stop'
|
|
3511
3997
|
*/
|
|
3512
|
-
loadingIcon = 'stop
|
|
3998
|
+
loadingIcon = 'stop';
|
|
3513
3999
|
/**
|
|
3514
4000
|
* Sets the SVG icon to be displayed when the **Action** button is in loading state.
|
|
3515
4001
|
*
|
|
3516
|
-
* @default
|
|
4002
|
+
* @default stopIcon
|
|
3517
4003
|
*/
|
|
3518
|
-
loadingSVGIcon =
|
|
4004
|
+
loadingSVGIcon = stopIcon;
|
|
3519
4005
|
/**
|
|
3520
4006
|
* Fires when the user clicks the Action button.
|
|
3521
4007
|
* @hidden
|
|
@@ -3527,8 +4013,8 @@ class PromptBoxActionButtonComponent extends PromptBoxBaseTool {
|
|
|
3527
4013
|
this.disabled = true;
|
|
3528
4014
|
this.rounded = 'full';
|
|
3529
4015
|
this.size = 'small';
|
|
3530
|
-
this.icon = 'arrow-up
|
|
3531
|
-
this.svgIcon =
|
|
4016
|
+
this.icon = 'arrow-up';
|
|
4017
|
+
this.svgIcon = arrowUpIcon;
|
|
3532
4018
|
}
|
|
3533
4019
|
/**
|
|
3534
4020
|
* @hidden
|
|
@@ -3566,7 +4052,7 @@ class PromptBoxActionButtonComponent extends PromptBoxBaseTool {
|
|
|
3566
4052
|
[themeColor]="themeColor"
|
|
3567
4053
|
(click)="handleClick()"
|
|
3568
4054
|
></button>
|
|
3569
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
4055
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
|
|
3570
4056
|
}
|
|
3571
4057
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PromptBoxActionButtonComponent, decorators: [{
|
|
3572
4058
|
type: Component,
|
|
@@ -3656,8 +4142,8 @@ class PromptBoxFileSelectButtonComponent extends PromptBoxBaseTool {
|
|
|
3656
4142
|
this.disabled = false;
|
|
3657
4143
|
this.fillMode = 'flat';
|
|
3658
4144
|
this.size = 'small';
|
|
3659
|
-
this.icon = 'paperclip
|
|
3660
|
-
this.svgIcon =
|
|
4145
|
+
this.icon = 'paperclip';
|
|
4146
|
+
this.svgIcon = paperclipIcon;
|
|
3661
4147
|
}
|
|
3662
4148
|
/**
|
|
3663
4149
|
* @hidden
|
|
@@ -3712,7 +4198,7 @@ class PromptBoxFileSelectButtonComponent extends PromptBoxBaseTool {
|
|
|
3712
4198
|
[accept]="accept"
|
|
3713
4199
|
(select)="handleSelect($event)"
|
|
3714
4200
|
></kendo-fileselect>
|
|
3715
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
4201
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: FileSelectComponent, selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }] });
|
|
3716
4202
|
}
|
|
3717
4203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PromptBoxFileSelectButtonComponent, decorators: [{
|
|
3718
4204
|
type: Component,
|
|
@@ -3813,12 +4299,13 @@ class PromptBoxFileComponent {
|
|
|
3813
4299
|
[attr.title]="textFor('removeFileTitle')"
|
|
3814
4300
|
[svgIcon]="deleteIcon"
|
|
3815
4301
|
icon="x"
|
|
4302
|
+
size="xsmall"
|
|
3816
4303
|
[disabled]="disabled"
|
|
3817
4304
|
(click)="remove.emit(promptBoxFile)"
|
|
3818
4305
|
fillMode="flat"
|
|
3819
4306
|
></button>
|
|
3820
4307
|
}
|
|
3821
|
-
`, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
4308
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
|
|
3822
4309
|
}
|
|
3823
4310
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PromptBoxFileComponent, decorators: [{
|
|
3824
4311
|
type: Component,
|
|
@@ -3841,6 +4328,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
3841
4328
|
[attr.title]="textFor('removeFileTitle')"
|
|
3842
4329
|
[svgIcon]="deleteIcon"
|
|
3843
4330
|
icon="x"
|
|
4331
|
+
size="xsmall"
|
|
3844
4332
|
[disabled]="disabled"
|
|
3845
4333
|
(click)="remove.emit(promptBoxFile)"
|
|
3846
4334
|
fillMode="flat"
|
|
@@ -5413,6 +5901,7 @@ class ChatFileComponent extends ChatItem {
|
|
|
5413
5901
|
[attr.title]="textFor('removeFileTitle')"
|
|
5414
5902
|
[svgIcon]="deleteIcon"
|
|
5415
5903
|
icon="x"
|
|
5904
|
+
size="xsmall"
|
|
5416
5905
|
(click)="remove.emit(chatFile)"
|
|
5417
5906
|
fillMode="flat"
|
|
5418
5907
|
></button>
|
|
@@ -5422,6 +5911,7 @@ class ChatFileComponent extends ChatItem {
|
|
|
5422
5911
|
[data]="fileActions"
|
|
5423
5912
|
[attr.title]="textFor('fileActionsTitle')"
|
|
5424
5913
|
fillMode="flat"
|
|
5914
|
+
size="small"
|
|
5425
5915
|
icon="more-vertical"
|
|
5426
5916
|
[svgIcon]="moreIcon"
|
|
5427
5917
|
(itemClick)="actionClick.emit($event)"
|
|
@@ -5430,7 +5920,7 @@ class ChatFileComponent extends ChatItem {
|
|
|
5430
5920
|
(close)="actionsToggle.emit(false)"
|
|
5431
5921
|
></kendo-dropdownbutton>
|
|
5432
5922
|
}
|
|
5433
|
-
`, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
5923
|
+
`, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }] });
|
|
5434
5924
|
}
|
|
5435
5925
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatFileComponent, decorators: [{
|
|
5436
5926
|
type: Component,
|
|
@@ -5457,6 +5947,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
5457
5947
|
[attr.title]="textFor('removeFileTitle')"
|
|
5458
5948
|
[svgIcon]="deleteIcon"
|
|
5459
5949
|
icon="x"
|
|
5950
|
+
size="xsmall"
|
|
5460
5951
|
(click)="remove.emit(chatFile)"
|
|
5461
5952
|
fillMode="flat"
|
|
5462
5953
|
></button>
|
|
@@ -5466,6 +5957,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
5466
5957
|
[data]="fileActions"
|
|
5467
5958
|
[attr.title]="textFor('fileActionsTitle')"
|
|
5468
5959
|
fillMode="flat"
|
|
5960
|
+
size="small"
|
|
5469
5961
|
icon="more-vertical"
|
|
5470
5962
|
[svgIcon]="moreIcon"
|
|
5471
5963
|
(itemClick)="actionClick.emit($event)"
|
|
@@ -5538,7 +6030,7 @@ const groupMessages = (acc, msg, isLastMessage) => {
|
|
|
5538
6030
|
messages: [msg],
|
|
5539
6031
|
author: msg.author,
|
|
5540
6032
|
timestamp: msg.timestamp,
|
|
5541
|
-
trackBy: msg
|
|
6033
|
+
trackBy: msg.id
|
|
5542
6034
|
});
|
|
5543
6035
|
}
|
|
5544
6036
|
};
|
|
@@ -6557,6 +7049,7 @@ class MessageBoxComponent {
|
|
|
6557
7049
|
icon="x"
|
|
6558
7050
|
(click)="removeReply()"
|
|
6559
7051
|
fillMode="flat"
|
|
7052
|
+
size="xsmall"
|
|
6560
7053
|
></button>
|
|
6561
7054
|
</div>
|
|
6562
7055
|
</ng-template>
|
|
@@ -6595,7 +7088,7 @@ class MessageBoxComponent {
|
|
|
6595
7088
|
} @if (messageBoxTemplate?.templateRef) {
|
|
6596
7089
|
<ng-template [ngTemplateOutlet]="messageBoxTemplate?.templateRef"></ng-template>
|
|
6597
7090
|
}
|
|
6598
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
7091
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PromptBoxComponent, selector: "kendo-promptbox", inputs: ["disabled", "focusableId", "loading", "placeholder", "readonly", "title", "mode", "rows", "maxTextAreaHeight", "value", "actionButton", "fileSelectButton", "speechToTextButton"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur", "promptAction", "selectAttachments", "fileRemove", "speechToTextClick", "speechToTextStart", "speechToTextEnd", "speechToTextError", "speechToTextResult"], exportAs: ["kendoPromptBox"] }, { kind: "component", type: PromptBoxCustomMessagesComponent, selector: "kendo-promptbox-messages" }, { kind: "directive", type: PromptBoxHeaderTemplateDirective, selector: "[kendoPromptBoxHeaderTemplate]" }, { kind: "component", type: PromptBoxStartAffixComponent, selector: "kendo-promptbox-start-affix", exportAs: ["kendoPromptBoxStartAffix"] }, { kind: "component", type: PromptBoxTopAffixComponent, selector: "kendo-promptbox-top-affix", exportAs: ["kendoPromptBoxTopAffix"] }, { kind: "component", type: PromptBoxEndAffixComponent, selector: "kendo-promptbox-end-affix", exportAs: ["kendoPromptBoxEndAffix"] }, { kind: "component", type: PromptBoxFileSelectButtonComponent, selector: "kendo-promptbox-fileselect-button", inputs: ["restrictions", "multiple", "accept"], outputs: ["selectAttachments"], exportAs: ["kendoPromptBoxFileSelectButton"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "component", type: SuggestedActionsComponent, selector: "kendo-chat-suggested-actions", inputs: ["actions", "suggestions", "tabbable", "type", "suggestionTemplate"], outputs: ["dispatchAction", "dispatchSuggestion"] }] });
|
|
6599
7092
|
}
|
|
6600
7093
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MessageBoxComponent, decorators: [{
|
|
6601
7094
|
type: Component,
|
|
@@ -6653,6 +7146,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
6653
7146
|
icon="x"
|
|
6654
7147
|
(click)="removeReply()"
|
|
6655
7148
|
fillMode="flat"
|
|
7149
|
+
size="xsmall"
|
|
6656
7150
|
></button>
|
|
6657
7151
|
</div>
|
|
6658
7152
|
</ng-template>
|
|
@@ -6763,8 +7257,16 @@ class MessageComponent extends ChatItem {
|
|
|
6763
7257
|
chatService;
|
|
6764
7258
|
localization;
|
|
6765
7259
|
cdr;
|
|
7260
|
+
zone;
|
|
6766
7261
|
set message(value) {
|
|
7262
|
+
const textChanged = this._message && value && this._message.text !== value.text;
|
|
6767
7263
|
this._message = value;
|
|
7264
|
+
if (textChanged) {
|
|
7265
|
+
this.parts = this.getFormattedTextParts(value.text);
|
|
7266
|
+
if (this.isMessageExpandable && !this.showExpandCollapseIcon) {
|
|
7267
|
+
this.updateExpandCollapseIconAfterStable();
|
|
7268
|
+
}
|
|
7269
|
+
}
|
|
6768
7270
|
}
|
|
6769
7271
|
get message() {
|
|
6770
7272
|
return this._message;
|
|
@@ -6802,7 +7304,7 @@ class MessageComponent extends ChatItem {
|
|
|
6802
7304
|
expandIcon = chevronDownIcon;
|
|
6803
7305
|
collapseIcon = chevronUpIcon;
|
|
6804
7306
|
downloadIcon = downloadIcon;
|
|
6805
|
-
resendIcon =
|
|
7307
|
+
resendIcon = arrowRotateCwIcon;
|
|
6806
7308
|
messageFailedIcon = warningTriangleIcon;
|
|
6807
7309
|
isMessageExpanded = false;
|
|
6808
7310
|
showExpandCollapseIcon = false;
|
|
@@ -6856,13 +7358,14 @@ class MessageComponent extends ChatItem {
|
|
|
6856
7358
|
}
|
|
6857
7359
|
subs = new Subscription();
|
|
6858
7360
|
_message;
|
|
6859
|
-
constructor(element, intl, chatService, localization, cdr) {
|
|
7361
|
+
constructor(element, intl, chatService, localization, cdr, zone) {
|
|
6860
7362
|
super();
|
|
6861
7363
|
this.element = element;
|
|
6862
7364
|
this.intl = intl;
|
|
6863
7365
|
this.chatService = chatService;
|
|
6864
7366
|
this.localization = localization;
|
|
6865
7367
|
this.cdr = cdr;
|
|
7368
|
+
this.zone = zone;
|
|
6866
7369
|
}
|
|
6867
7370
|
ngOnInit() {
|
|
6868
7371
|
this.fileActions = this.getFileActions();
|
|
@@ -6873,14 +7376,20 @@ class MessageComponent extends ChatItem {
|
|
|
6873
7376
|
this.subs.add(settingsChange$.subscribe(() => {
|
|
6874
7377
|
this.fileActions = this.getFileActions();
|
|
6875
7378
|
this.toolbarActions = this.getToolbarActions();
|
|
6876
|
-
|
|
6877
|
-
this.
|
|
6878
|
-
}
|
|
7379
|
+
if (this.isMessageExpandable) {
|
|
7380
|
+
this.updateExpandCollapseIconAfterStable();
|
|
7381
|
+
}
|
|
6879
7382
|
}));
|
|
6880
7383
|
this.subs.add(this.chatService.allowMessageCollapseChange$.subscribe(() => {
|
|
6881
|
-
|
|
6882
|
-
this.
|
|
6883
|
-
}
|
|
7384
|
+
if (this.isMessageExpandable) {
|
|
7385
|
+
this.updateExpandCollapseIconAfterStable();
|
|
7386
|
+
}
|
|
7387
|
+
else {
|
|
7388
|
+
this.showExpandCollapseIcon = false;
|
|
7389
|
+
}
|
|
7390
|
+
}));
|
|
7391
|
+
this.subs.add(this.chatService.messageToolbarActionsChange$.subscribe(() => {
|
|
7392
|
+
this.toolbarActions = this.getToolbarActions();
|
|
6884
7393
|
}));
|
|
6885
7394
|
if (this.message.id) {
|
|
6886
7395
|
this.chatService.registerMessageElement(this.message.id, this.element);
|
|
@@ -6888,8 +7397,9 @@ class MessageComponent extends ChatItem {
|
|
|
6888
7397
|
this.parts = this.getFormattedTextParts(this.message.text);
|
|
6889
7398
|
}
|
|
6890
7399
|
ngAfterViewInit() {
|
|
6891
|
-
|
|
6892
|
-
|
|
7400
|
+
if (this.isMessageExpandable) {
|
|
7401
|
+
this.updateExpandCollapseIconAfterStable();
|
|
7402
|
+
}
|
|
6893
7403
|
}
|
|
6894
7404
|
ngOnDestroy() {
|
|
6895
7405
|
if (this.message.id) {
|
|
@@ -6960,6 +7470,7 @@ class MessageComponent extends ChatItem {
|
|
|
6960
7470
|
event.stopImmediatePropagation();
|
|
6961
7471
|
this.isMessageExpanded = !this.isMessageExpanded;
|
|
6962
7472
|
this.chatService.toggleMessageState = false;
|
|
7473
|
+
this.cdr.detectChanges();
|
|
6963
7474
|
}
|
|
6964
7475
|
onExpandableKeydown(event) {
|
|
6965
7476
|
const key = normalizeKeys(event);
|
|
@@ -7074,7 +7585,13 @@ class MessageComponent extends ChatItem {
|
|
|
7074
7585
|
: this.chatService.fileActions || [];
|
|
7075
7586
|
return transformActions(actions);
|
|
7076
7587
|
}
|
|
7077
|
-
|
|
7588
|
+
updateExpandCollapseIconAfterStable() {
|
|
7589
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
7590
|
+
this.showExpandCollapseIcon = this.calculateExpandCollapseIconVisibility();
|
|
7591
|
+
this.cdr.detectChanges();
|
|
7592
|
+
}));
|
|
7593
|
+
}
|
|
7594
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MessageComponent, deps: [{ token: i0.ElementRef }, { token: i1$1.IntlService }, { token: ChatService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
7078
7595
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: MessageComponent, isStandalone: true, selector: "kendo-chat-message", inputs: { message: "message", tabbable: "tabbable", authorMessageContentTemplate: "authorMessageContentTemplate", receiverMessageContentTemplate: "receiverMessageContentTemplate", messageContentTemplate: "messageContentTemplate", authorMessageTemplate: "authorMessageTemplate", receiverMessageTemplate: "receiverMessageTemplate", messageTemplate: "messageTemplate", statusTemplate: "statusTemplate", showMessageTime: "showMessageTime", authorId: "authorId" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.k-message": "this.cssClass", "class.k-message-failed": "this.failedClass", "class.k-message-removed": "this.removedClass", "attr.tabIndex": "this.tabIndex" } }, providers: [
|
|
7079
7596
|
{
|
|
7080
7597
|
provide: ChatItem,
|
|
@@ -7094,7 +7611,7 @@ class MessageComponent extends ChatItem {
|
|
|
7094
7611
|
</div>
|
|
7095
7612
|
</div>
|
|
7096
7613
|
} @if (!message.typing) { @if (useCustomContentTemplate) { @if (message.failed) {
|
|
7097
|
-
<button kendoButton class="k-resend-button" size="
|
|
7614
|
+
<button kendoButton class="k-resend-button" size="xsmall" fillMode="clear" icon="arrow-rotate-cw" [svgIcon]="resendIcon" (click)="onResendMessage($event)"></button>
|
|
7098
7615
|
}
|
|
7099
7616
|
<div
|
|
7100
7617
|
class="k-chat-bubble k-bubble"
|
|
@@ -7130,7 +7647,7 @@ class MessageComponent extends ChatItem {
|
|
|
7130
7647
|
}
|
|
7131
7648
|
</div>
|
|
7132
7649
|
} @if (!useCustomContentTemplate && hasMessageContent) { @if (message.failed) {
|
|
7133
|
-
<button kendoButton class="k-resend-button" size="
|
|
7650
|
+
<button kendoButton class="k-resend-button" size="xsmall" fillMode="clear" icon="arrow-rotate-cw" [svgIcon]="resendIcon" (click)="onResendMessage($event)"></button>
|
|
7134
7651
|
}
|
|
7135
7652
|
<div
|
|
7136
7653
|
class="k-chat-bubble k-bubble"
|
|
@@ -7159,7 +7676,7 @@ class MessageComponent extends ChatItem {
|
|
|
7159
7676
|
</span>
|
|
7160
7677
|
} @if (!message.isDeleted && parts.length > 0) {
|
|
7161
7678
|
<span class="k-chat-bubble-text">
|
|
7162
|
-
@for (part of parts; track
|
|
7679
|
+
@for (part of parts; track $index) { @if (part.type === 'text') {{{part.content}}} @if (part.type ===
|
|
7163
7680
|
'link') {<a [href]="part.href" target="_blank">{{ part.content }}</a
|
|
7164
7681
|
>} }
|
|
7165
7682
|
</span>
|
|
@@ -7172,7 +7689,7 @@ class MessageComponent extends ChatItem {
|
|
|
7172
7689
|
'k-files-vertical': chatService.messageFilesLayout === 'vertical'
|
|
7173
7690
|
}"
|
|
7174
7691
|
>
|
|
7175
|
-
@for (file of message.files; track file) {
|
|
7692
|
+
@for (file of message.files; track file.id) {
|
|
7176
7693
|
<li
|
|
7177
7694
|
class="k-file-box"
|
|
7178
7695
|
[chatFile]="file"
|
|
@@ -7186,7 +7703,7 @@ class MessageComponent extends ChatItem {
|
|
|
7186
7703
|
} @else {
|
|
7187
7704
|
<ul class="k-file-box-wrapper">
|
|
7188
7705
|
<div class="k-files-scroll">
|
|
7189
|
-
@for (file of message.files; track file) {
|
|
7706
|
+
@for (file of message.files; track file.id) {
|
|
7190
7707
|
<li
|
|
7191
7708
|
class="k-file-box"
|
|
7192
7709
|
[chatFile]="file"
|
|
@@ -7271,8 +7788,8 @@ class MessageComponent extends ChatItem {
|
|
|
7271
7788
|
}
|
|
7272
7789
|
</div>
|
|
7273
7790
|
} } @if (showToolbar) {
|
|
7274
|
-
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
|
|
7275
|
-
@for (action of toolbarActions; track action) {
|
|
7791
|
+
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat" size="small">
|
|
7792
|
+
@for (action of toolbarActions; track action.id) {
|
|
7276
7793
|
<kendo-toolbar-button
|
|
7277
7794
|
fillMode="flat"
|
|
7278
7795
|
[icon]="action.icon"
|
|
@@ -7285,7 +7802,7 @@ class MessageComponent extends ChatItem {
|
|
|
7285
7802
|
}
|
|
7286
7803
|
</kendo-toolbar>
|
|
7287
7804
|
}
|
|
7288
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
7805
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: ChatFileComponent, selector: "li[chatFile]", inputs: ["chatFile", "removable", "fileActions"], outputs: ["remove", "actionClick", "actionsToggle", "actionButtonClick"] }, { kind: "component", type: ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "fillMode", "tabindex", "size", "tabIndex", "showIcon", "showText"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { kind: "component", type: ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "rounded", "themeColor", "icon", "iconClass", "svgIcon", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }] });
|
|
7289
7806
|
}
|
|
7290
7807
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MessageComponent, decorators: [{
|
|
7291
7808
|
type: Component,
|
|
@@ -7311,7 +7828,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7311
7828
|
</div>
|
|
7312
7829
|
</div>
|
|
7313
7830
|
} @if (!message.typing) { @if (useCustomContentTemplate) { @if (message.failed) {
|
|
7314
|
-
<button kendoButton class="k-resend-button" size="
|
|
7831
|
+
<button kendoButton class="k-resend-button" size="xsmall" fillMode="clear" icon="arrow-rotate-cw" [svgIcon]="resendIcon" (click)="onResendMessage($event)"></button>
|
|
7315
7832
|
}
|
|
7316
7833
|
<div
|
|
7317
7834
|
class="k-chat-bubble k-bubble"
|
|
@@ -7347,7 +7864,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7347
7864
|
}
|
|
7348
7865
|
</div>
|
|
7349
7866
|
} @if (!useCustomContentTemplate && hasMessageContent) { @if (message.failed) {
|
|
7350
|
-
<button kendoButton class="k-resend-button" size="
|
|
7867
|
+
<button kendoButton class="k-resend-button" size="xsmall" fillMode="clear" icon="arrow-rotate-cw" [svgIcon]="resendIcon" (click)="onResendMessage($event)"></button>
|
|
7351
7868
|
}
|
|
7352
7869
|
<div
|
|
7353
7870
|
class="k-chat-bubble k-bubble"
|
|
@@ -7376,7 +7893,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7376
7893
|
</span>
|
|
7377
7894
|
} @if (!message.isDeleted && parts.length > 0) {
|
|
7378
7895
|
<span class="k-chat-bubble-text">
|
|
7379
|
-
@for (part of parts; track
|
|
7896
|
+
@for (part of parts; track $index) { @if (part.type === 'text') {{{part.content}}} @if (part.type ===
|
|
7380
7897
|
'link') {<a [href]="part.href" target="_blank">{{ part.content }}</a
|
|
7381
7898
|
>} }
|
|
7382
7899
|
</span>
|
|
@@ -7389,7 +7906,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7389
7906
|
'k-files-vertical': chatService.messageFilesLayout === 'vertical'
|
|
7390
7907
|
}"
|
|
7391
7908
|
>
|
|
7392
|
-
@for (file of message.files; track file) {
|
|
7909
|
+
@for (file of message.files; track file.id) {
|
|
7393
7910
|
<li
|
|
7394
7911
|
class="k-file-box"
|
|
7395
7912
|
[chatFile]="file"
|
|
@@ -7403,7 +7920,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7403
7920
|
} @else {
|
|
7404
7921
|
<ul class="k-file-box-wrapper">
|
|
7405
7922
|
<div class="k-files-scroll">
|
|
7406
|
-
@for (file of message.files; track file) {
|
|
7923
|
+
@for (file of message.files; track file.id) {
|
|
7407
7924
|
<li
|
|
7408
7925
|
class="k-file-box"
|
|
7409
7926
|
[chatFile]="file"
|
|
@@ -7488,8 +8005,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7488
8005
|
}
|
|
7489
8006
|
</div>
|
|
7490
8007
|
} } @if (showToolbar) {
|
|
7491
|
-
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat">
|
|
7492
|
-
@for (action of toolbarActions; track action) {
|
|
8008
|
+
<kendo-toolbar class="k-chat-message-toolbar" fillMode="flat" size="small">
|
|
8009
|
+
@for (action of toolbarActions; track action.id) {
|
|
7493
8010
|
<kendo-toolbar-button
|
|
7494
8011
|
fillMode="flat"
|
|
7495
8012
|
[icon]="action.icon"
|
|
@@ -7516,7 +8033,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
7516
8033
|
ButtonComponent,
|
|
7517
8034
|
],
|
|
7518
8035
|
}]
|
|
7519
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1$1.IntlService }, { type: ChatService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { message: [{
|
|
8036
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1$1.IntlService }, { type: ChatService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { message: [{
|
|
7520
8037
|
type: Input
|
|
7521
8038
|
}], tabbable: [{
|
|
7522
8039
|
type: Input
|
|
@@ -7816,7 +8333,7 @@ class MessageAttachmentsComponent extends ChatItem {
|
|
|
7816
8333
|
>
|
|
7817
8334
|
</button>
|
|
7818
8335
|
}
|
|
7819
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
8336
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: AttachmentComponent, selector: "kendo-chat-attachment", inputs: ["attachment", "template"] }] });
|
|
7820
8337
|
}
|
|
7821
8338
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MessageAttachmentsComponent, decorators: [{
|
|
7822
8339
|
type: Component,
|
|
@@ -8074,6 +8591,7 @@ class MessageListComponent {
|
|
|
8074
8591
|
item.selected = true;
|
|
8075
8592
|
this.selectedItem = item;
|
|
8076
8593
|
}
|
|
8594
|
+
this.chatService.layoutChangeInProgress = true;
|
|
8077
8595
|
this.cdr.detectChanges();
|
|
8078
8596
|
}
|
|
8079
8597
|
this.chatService.toggleMessageState = false;
|
|
@@ -8238,7 +8756,7 @@ class MessageListComponent {
|
|
|
8238
8756
|
<div class="k-message-group-content">
|
|
8239
8757
|
@if (showGroupAuthor(group)) {
|
|
8240
8758
|
<p class="k-message-author">{{ group.author.name }}</p>
|
|
8241
|
-
} @for (msg of group.messages; track msg; let firstMessage = $first; let lastMessage = $last) { @if
|
|
8759
|
+
} @for (msg of group.messages; track msg.id; let firstMessage = $first; let lastMessage = $last) { @if
|
|
8242
8760
|
(msg.user?.avatarUrl) {
|
|
8243
8761
|
<div class="k-avatar">
|
|
8244
8762
|
<span class="k-avatar-image">
|
|
@@ -8346,7 +8864,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
8346
8864
|
<div class="k-message-group-content">
|
|
8347
8865
|
@if (showGroupAuthor(group)) {
|
|
8348
8866
|
<p class="k-message-author">{{ group.author.name }}</p>
|
|
8349
|
-
} @for (msg of group.messages; track msg; let firstMessage = $first; let lastMessage = $last) { @if
|
|
8867
|
+
} @for (msg of group.messages; track msg.id; let firstMessage = $first; let lastMessage = $last) { @if
|
|
8350
8868
|
(msg.user?.avatarUrl) {
|
|
8351
8869
|
<div class="k-avatar">
|
|
8352
8870
|
<span class="k-avatar-image">
|
|
@@ -8666,6 +9184,62 @@ class ChatComponent {
|
|
|
8666
9184
|
get sendButtonSettings() {
|
|
8667
9185
|
return this.sendButton;
|
|
8668
9186
|
}
|
|
9187
|
+
/**
|
|
9188
|
+
* Controls the scrolling behavior of the message list.
|
|
9189
|
+
*
|
|
9190
|
+
* @default 'scrollable'
|
|
9191
|
+
*/
|
|
9192
|
+
scrollMode = 'scrollable';
|
|
9193
|
+
/**
|
|
9194
|
+
* Sets the number of messages loaded per page in endless scroll mode.
|
|
9195
|
+
* Ignored in `scrollable` mode.
|
|
9196
|
+
*
|
|
9197
|
+
* @default 50
|
|
9198
|
+
*/
|
|
9199
|
+
pageSize = 50;
|
|
9200
|
+
/**
|
|
9201
|
+
* Sets the minimum distance from the top of the visible message area that prevents auto-scrolling when a new receiver message arrives.
|
|
9202
|
+
* Accepts a percentage string (for example, `'30%'`) or a pixel value as a number. Set to `0` to always auto-scroll to new messages.
|
|
9203
|
+
*
|
|
9204
|
+
* Has no effect on author messages, which always scroll to the bottom.
|
|
9205
|
+
*
|
|
9206
|
+
* For more details, refer to the [Auto-Scroll Threshold](slug:scroll_modes_chat#auto-scroll-threshold) article.
|
|
9207
|
+
*
|
|
9208
|
+
* @default '20%'
|
|
9209
|
+
*/
|
|
9210
|
+
autoScrollThreshold = '20%';
|
|
9211
|
+
/**
|
|
9212
|
+
* Sets the total number of messages in the conversation when using endless scrolling with remote data source. For more details, refer to the [Endless Scrolling with Remote Data](slug:scroll_modes_chat#remote-data) section in the documentation.
|
|
9213
|
+
*/
|
|
9214
|
+
total;
|
|
9215
|
+
/**
|
|
9216
|
+
* Sets the index of the first message in the currently loaded batch within the full conversation.
|
|
9217
|
+
* Used with remote data sources in endless scroll mode to compute the range for the next [`loadMore`](slug:api_conversational-ui_chatcomponent#loadMore) call.
|
|
9218
|
+
* For more details, refer to the [Endless Scrolling with Remote Data](slug:scroll_modes_chat#remote-data) section in the documentation.
|
|
9219
|
+
*/
|
|
9220
|
+
startIndex;
|
|
9221
|
+
/**
|
|
9222
|
+
* Sets the exclusive end index of the currently loaded batch within the full conversation.
|
|
9223
|
+
* Used with remote data sources in endless scroll mode to determine whether more messages exist beyond the current batch.
|
|
9224
|
+
* For more details, refer to the [Endless Scrolling with Remote Data](slug:scroll_modes_chat#remote-data) section in the documentation.
|
|
9225
|
+
*/
|
|
9226
|
+
endIndex;
|
|
9227
|
+
/**
|
|
9228
|
+
* Sets the full set of pinned messages in the conversation.
|
|
9229
|
+
* Used with remote data sources in endless scroll mode to render the pinned message indicator when the pinned message is outside the currently loaded batch.
|
|
9230
|
+
* For more details, refer to the [Endless Scrolling with Remote Data](slug:scroll_modes_chat#remote-data) section in the documentation.
|
|
9231
|
+
*
|
|
9232
|
+
* @default []
|
|
9233
|
+
*/
|
|
9234
|
+
pinnedMessages = [];
|
|
9235
|
+
/**
|
|
9236
|
+
* Sets the messages that serve as reply targets for messages in the currently loaded batch but exist outside it.
|
|
9237
|
+
* Used with remote data sources in endless scroll mode to render reply previews when the replied-to message is not in the current batch.
|
|
9238
|
+
* For more details, refer to the [Endless Scrolling with Remote Data](slug:scroll_modes_chat#remote-data) section in the documentation.
|
|
9239
|
+
*
|
|
9240
|
+
* @default []
|
|
9241
|
+
*/
|
|
9242
|
+
repliedToMessages = [];
|
|
8669
9243
|
/**
|
|
8670
9244
|
* Sets the names of the model fields from which the Chat reads its data.
|
|
8671
9245
|
* Lets you map custom data types to the expected `Message` format.
|
|
@@ -8743,6 +9317,14 @@ class ChatComponent {
|
|
|
8743
9317
|
* Fires when the user types in the message input box.
|
|
8744
9318
|
*/
|
|
8745
9319
|
inputValueChange = new EventEmitter();
|
|
9320
|
+
/**
|
|
9321
|
+
* Fires when the user scrolls near the edge of the rendered message window in endless scroll mode.
|
|
9322
|
+
*/
|
|
9323
|
+
loadMore = new EventEmitter();
|
|
9324
|
+
/**
|
|
9325
|
+
* Fires when the user clicks a referenced message (pinned indicator or reply preview).
|
|
9326
|
+
*/
|
|
9327
|
+
referencedMessageClick = new EventEmitter();
|
|
8746
9328
|
get className() {
|
|
8747
9329
|
return 'k-chat';
|
|
8748
9330
|
}
|
|
@@ -8793,6 +9375,43 @@ class ChatComponent {
|
|
|
8793
9375
|
}
|
|
8794
9376
|
return this.messages;
|
|
8795
9377
|
}
|
|
9378
|
+
/**
|
|
9379
|
+
* @hidden
|
|
9380
|
+
* Returns `true` when the Chat is in remote endless scroll mode.
|
|
9381
|
+
* Remote mode is active whenever the consumer provides a `total`.
|
|
9382
|
+
*/
|
|
9383
|
+
get isRemoteMode() {
|
|
9384
|
+
return this.scrollMode === 'endless'
|
|
9385
|
+
&& isPresent(this.total);
|
|
9386
|
+
}
|
|
9387
|
+
/**
|
|
9388
|
+
* @hidden
|
|
9389
|
+
* Returns the messages to render — sliced in endless mode, full in scrollable mode.
|
|
9390
|
+
* In remote mode, returns processedMessages as-is (consumer already provides only the current batch).
|
|
9391
|
+
*/
|
|
9392
|
+
get renderedMessages() {
|
|
9393
|
+
const all = this.processedMessages;
|
|
9394
|
+
if (!all || all.length === 0) {
|
|
9395
|
+
return [];
|
|
9396
|
+
}
|
|
9397
|
+
if (this.scrollMode === 'endless') {
|
|
9398
|
+
if (this.isRemoteMode) {
|
|
9399
|
+
return all;
|
|
9400
|
+
}
|
|
9401
|
+
const start = this.endlessState.startIndex;
|
|
9402
|
+
const end = this.endlessState.endIndex;
|
|
9403
|
+
if (all !== this._renderedMessagesSource ||
|
|
9404
|
+
start !== this._renderedMessagesStart ||
|
|
9405
|
+
end !== this._renderedMessagesEnd) {
|
|
9406
|
+
this._cachedRenderedMessages = all.slice(start, end);
|
|
9407
|
+
this._renderedMessagesSource = all;
|
|
9408
|
+
this._renderedMessagesStart = start;
|
|
9409
|
+
this._renderedMessagesEnd = end;
|
|
9410
|
+
}
|
|
9411
|
+
return this._cachedRenderedMessages;
|
|
9412
|
+
}
|
|
9413
|
+
return all;
|
|
9414
|
+
}
|
|
8796
9415
|
/**
|
|
8797
9416
|
* @hidden
|
|
8798
9417
|
*/
|
|
@@ -8825,7 +9444,7 @@ class ChatComponent {
|
|
|
8825
9444
|
/**
|
|
8826
9445
|
* @hidden
|
|
8827
9446
|
*/
|
|
8828
|
-
pinIcon =
|
|
9447
|
+
pinIcon = pinIcon;
|
|
8829
9448
|
/**
|
|
8830
9449
|
* @hidden
|
|
8831
9450
|
*/
|
|
@@ -8837,7 +9456,20 @@ class ChatComponent {
|
|
|
8837
9456
|
/**
|
|
8838
9457
|
* @hidden
|
|
8839
9458
|
*/
|
|
8840
|
-
scrollToBottomIcon =
|
|
9459
|
+
scrollToBottomIcon = arrowDownIcon;
|
|
9460
|
+
/**
|
|
9461
|
+
* @hidden
|
|
9462
|
+
*/
|
|
9463
|
+
endlessState = new EndlessScrollState();
|
|
9464
|
+
/**
|
|
9465
|
+
* @hidden
|
|
9466
|
+
*/
|
|
9467
|
+
showLicenseWatermark = false;
|
|
9468
|
+
/**
|
|
9469
|
+
* @hidden
|
|
9470
|
+
*/
|
|
9471
|
+
licenseMessage;
|
|
9472
|
+
anchor;
|
|
8841
9473
|
direction;
|
|
8842
9474
|
subs = new Subscription();
|
|
8843
9475
|
_modelFields = defaultModelFields;
|
|
@@ -8848,13 +9480,27 @@ class ChatComponent {
|
|
|
8848
9480
|
_lastModelFields = null;
|
|
8849
9481
|
_cachedContextMenuActions = [];
|
|
8850
9482
|
_lastContextMenuActionsReference = null;
|
|
9483
|
+
_previousMessagesLength = 0;
|
|
9484
|
+
_previousLastMessageId = null;
|
|
9485
|
+
_hasProcessedMessages = false;
|
|
9486
|
+
_pendingScrollAction = null;
|
|
9487
|
+
_scrollHandledBeforePaint = false;
|
|
9488
|
+
_lastNewMessageId = null;
|
|
9489
|
+
_cachedRenderedMessages = [];
|
|
9490
|
+
_renderedMessagesSource = null;
|
|
9491
|
+
_renderedMessagesStart = -1;
|
|
9492
|
+
_renderedMessagesEnd = -1;
|
|
9493
|
+
_pendingRemoteScrollToMessageId = null;
|
|
9494
|
+
_remoteScrollToBottom = false;
|
|
8851
9495
|
constructor(localization, zone, renderer, element, chatService) {
|
|
8852
9496
|
this.localization = localization;
|
|
8853
9497
|
this.zone = zone;
|
|
8854
9498
|
this.renderer = renderer;
|
|
8855
9499
|
this.element = element;
|
|
8856
9500
|
this.chatService = chatService;
|
|
8857
|
-
validatePackage(packageMetadata);
|
|
9501
|
+
const isValid = validatePackage(packageMetadata);
|
|
9502
|
+
this.licenseMessage = getLicenseMessage(packageMetadata);
|
|
9503
|
+
this.showLicenseWatermark = shouldShowValidationUI(isValid);
|
|
8858
9504
|
this.direction = localization.rtl ? 'rtl' : 'ltr';
|
|
8859
9505
|
this.subs.add(localization.changes.subscribe(({ rtl }) => {
|
|
8860
9506
|
this.direction = rtl ? 'rtl' : 'ltr';
|
|
@@ -8900,17 +9546,53 @@ class ChatComponent {
|
|
|
8900
9546
|
}));
|
|
8901
9547
|
this.pinnedMessage = this.findLastPinnedMessage();
|
|
8902
9548
|
this.chatService.authorId = this.authorId;
|
|
9549
|
+
this.chatService.repliedToMessages = this.repliedToMessages || [];
|
|
9550
|
+
this.initEndlessScroll();
|
|
9551
|
+
this.subs.add(this.chatService.replyReferenceClick$.subscribe((messageId) => {
|
|
9552
|
+
this.handleReferencedMessageClick(messageId, 'reply');
|
|
9553
|
+
}));
|
|
8903
9554
|
}
|
|
8904
9555
|
/**
|
|
8905
9556
|
* @hidden
|
|
8906
9557
|
*/
|
|
8907
9558
|
ngOnChanges(changes) {
|
|
8908
|
-
this.zone.runOutsideAngular(() => setTimeout(() => {
|
|
8909
|
-
this.messageList.element.nativeElement.style.flex = '1 1 auto';
|
|
8910
|
-
}));
|
|
8911
9559
|
if (isChanged('messages', changes, false)) {
|
|
8912
9560
|
this.pinnedMessage = this.findLastPinnedMessage();
|
|
8913
9561
|
this.chatService.messages = this.processedMessages;
|
|
9562
|
+
if (this.isRemoteMode) {
|
|
9563
|
+
const skipDetectAndSchedule = this.endlessState.isLoading || !!this._pendingRemoteScrollToMessageId;
|
|
9564
|
+
if (!skipDetectAndSchedule) {
|
|
9565
|
+
this.detectNewMessageScrollAction();
|
|
9566
|
+
}
|
|
9567
|
+
this.handleRemoteMessagesChange();
|
|
9568
|
+
if (!skipDetectAndSchedule) {
|
|
9569
|
+
this.scheduleNewMessageScroll();
|
|
9570
|
+
}
|
|
9571
|
+
}
|
|
9572
|
+
else {
|
|
9573
|
+
this.detectNewMessageScrollAction();
|
|
9574
|
+
this.handleMessagesChange();
|
|
9575
|
+
this.scheduleNewMessageScroll();
|
|
9576
|
+
}
|
|
9577
|
+
this.handlePendingRemoteScroll();
|
|
9578
|
+
}
|
|
9579
|
+
if (isChanged('pinnedMessages', changes, false)) {
|
|
9580
|
+
this.pinnedMessage = this.findLastPinnedMessage();
|
|
9581
|
+
}
|
|
9582
|
+
if (isChanged('repliedToMessages', changes, false)) {
|
|
9583
|
+
this.chatService.repliedToMessages = this.repliedToMessages || [];
|
|
9584
|
+
}
|
|
9585
|
+
this.validateRemoteInputs();
|
|
9586
|
+
if (isChanged('scrollMode', changes, false)) {
|
|
9587
|
+
this.initEndlessScroll();
|
|
9588
|
+
}
|
|
9589
|
+
if (isChanged('pageSize', changes, false) && this.scrollMode === 'endless') {
|
|
9590
|
+
this.endlessState.init(this.processedMessages?.length || 0, this.pageSize);
|
|
9591
|
+
}
|
|
9592
|
+
if (this.isRemoteMode && (isChanged('startIndex', changes, false) ||
|
|
9593
|
+
isChanged('endIndex', changes, false) ||
|
|
9594
|
+
isChanged('total', changes, false))) {
|
|
9595
|
+
this.endlessState.syncFromInputs(this.startIndex, this.endIndex, this.total);
|
|
8914
9596
|
}
|
|
8915
9597
|
if (isChanged('height', changes, false)) {
|
|
8916
9598
|
this.renderer.setStyle(this.element.nativeElement, 'height', `${processCssValue(this.height)}`);
|
|
@@ -8980,9 +9662,130 @@ class ChatComponent {
|
|
|
8980
9662
|
/**
|
|
8981
9663
|
* @hidden
|
|
8982
9664
|
*/
|
|
8983
|
-
scrollToPinnedMessage() {
|
|
9665
|
+
scrollToPinnedMessage(event) {
|
|
9666
|
+
if (event && event.target?.closest('button')) {
|
|
9667
|
+
return;
|
|
9668
|
+
}
|
|
8984
9669
|
if (this.pinnedMessage) {
|
|
8985
|
-
this.
|
|
9670
|
+
this.handleReferencedMessageClick(this.pinnedMessage.id, 'pinned');
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
/**
|
|
9674
|
+
* @hidden
|
|
9675
|
+
*/
|
|
9676
|
+
onNearTop() {
|
|
9677
|
+
if (this.scrollMode !== 'endless' || this.endlessState.isLoading) {
|
|
9678
|
+
return;
|
|
9679
|
+
}
|
|
9680
|
+
if (this.isRemoteMode) {
|
|
9681
|
+
if (this.startIndex <= 0) {
|
|
9682
|
+
return;
|
|
9683
|
+
}
|
|
9684
|
+
this.endlessState.isLoading = true;
|
|
9685
|
+
this.anchor?.recordScrollHeight();
|
|
9686
|
+
this.anchor?.setAriaLive('off');
|
|
9687
|
+
const reqStart = Math.max(0, this.startIndex - this.pageSize);
|
|
9688
|
+
this.loadMore.emit({ startIndex: reqStart, endIndex: this.endIndex });
|
|
9689
|
+
return;
|
|
9690
|
+
}
|
|
9691
|
+
const range = this.endlessState.extendUp();
|
|
9692
|
+
if (range) {
|
|
9693
|
+
this.endlessState.isLoading = true;
|
|
9694
|
+
this.anchor?.recordScrollHeight();
|
|
9695
|
+
this.anchor?.setAriaLive('off');
|
|
9696
|
+
this.loadMore.emit({ startIndex: range.start, endIndex: range.end });
|
|
9697
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9698
|
+
this.anchor?.preserveScrollPosition();
|
|
9699
|
+
this.anchor?.setAriaLive('polite');
|
|
9700
|
+
this.endlessState.isLoading = false;
|
|
9701
|
+
}));
|
|
9702
|
+
}
|
|
9703
|
+
}
|
|
9704
|
+
/**
|
|
9705
|
+
* @hidden
|
|
9706
|
+
*/
|
|
9707
|
+
onNearBottom() {
|
|
9708
|
+
if (this.scrollMode !== 'endless' || this.endlessState.isLoading) {
|
|
9709
|
+
return;
|
|
9710
|
+
}
|
|
9711
|
+
if (this.isRemoteMode) {
|
|
9712
|
+
if (this.endIndex >= this.total) {
|
|
9713
|
+
return;
|
|
9714
|
+
}
|
|
9715
|
+
this.endlessState.isLoading = true;
|
|
9716
|
+
this.anchor?.setAriaLive('off');
|
|
9717
|
+
const reqEnd = Math.min(this.total, this.endIndex + this.pageSize);
|
|
9718
|
+
this.loadMore.emit({ startIndex: this.startIndex, endIndex: reqEnd });
|
|
9719
|
+
return;
|
|
9720
|
+
}
|
|
9721
|
+
const range = this.endlessState.extendDown();
|
|
9722
|
+
if (range) {
|
|
9723
|
+
this.endlessState.isLoading = true;
|
|
9724
|
+
this.loadMore.emit({ startIndex: range.start, endIndex: range.end });
|
|
9725
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9726
|
+
this.endlessState.isLoading = false;
|
|
9727
|
+
}));
|
|
9728
|
+
}
|
|
9729
|
+
}
|
|
9730
|
+
/**
|
|
9731
|
+
* @hidden
|
|
9732
|
+
*/
|
|
9733
|
+
onScrollToBottomClick() {
|
|
9734
|
+
if (this.scrollMode === 'endless' && !this.endlessState.isAtEnd) {
|
|
9735
|
+
if (this.isRemoteMode) {
|
|
9736
|
+
this.endlessState.isLoading = true;
|
|
9737
|
+
this._remoteScrollToBottom = true;
|
|
9738
|
+
this.autoScroll = true;
|
|
9739
|
+
const reqStart = Math.max(0, this.total - this.pageSize);
|
|
9740
|
+
this.loadMore.emit({ startIndex: reqStart, endIndex: this.total });
|
|
9741
|
+
return;
|
|
9742
|
+
}
|
|
9743
|
+
this.anchor?.lockForMessageScroll();
|
|
9744
|
+
const range = this.endlessState.jumpToEnd();
|
|
9745
|
+
this.loadMore.emit({ startIndex: range.start, endIndex: range.end });
|
|
9746
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9747
|
+
this.anchor?.scrollToBottomWithSettle(() => {
|
|
9748
|
+
this.anchor?.unlockForMessageScroll();
|
|
9749
|
+
});
|
|
9750
|
+
}));
|
|
9751
|
+
}
|
|
9752
|
+
else {
|
|
9753
|
+
this.anchor?.scrollToBottom();
|
|
9754
|
+
}
|
|
9755
|
+
}
|
|
9756
|
+
/**
|
|
9757
|
+
* @hidden
|
|
9758
|
+
*/
|
|
9759
|
+
handleReferencedMessageClick(messageId, type) {
|
|
9760
|
+
this.referencedMessageClick.emit({ id: messageId, type });
|
|
9761
|
+
this.autoScroll = false;
|
|
9762
|
+
if (this.scrollMode === 'endless') {
|
|
9763
|
+
if (this.isRemoteMode) {
|
|
9764
|
+
this.handleRemoteReferencedMessageClick(messageId);
|
|
9765
|
+
return;
|
|
9766
|
+
}
|
|
9767
|
+
const allMessages = this.processedMessages;
|
|
9768
|
+
const targetIndex = allMessages.findIndex(m => m.id === messageId);
|
|
9769
|
+
if (targetIndex === -1) {
|
|
9770
|
+
return;
|
|
9771
|
+
}
|
|
9772
|
+
if (this.endlessState.contains(targetIndex)) {
|
|
9773
|
+
this.anchor?.lockForMessageScroll();
|
|
9774
|
+
this.chatService.scrollToMessage(messageId, 'auto');
|
|
9775
|
+
this.anchor?.unlockForMessageScroll();
|
|
9776
|
+
}
|
|
9777
|
+
else {
|
|
9778
|
+
this.anchor?.lockForMessageScroll();
|
|
9779
|
+
const range = this.endlessState.jumpTo(targetIndex);
|
|
9780
|
+
this.loadMore.emit({ startIndex: range.start, endIndex: range.end });
|
|
9781
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9782
|
+
this.chatService.scrollToMessage(messageId, 'auto');
|
|
9783
|
+
this.anchor?.unlockForMessageScroll();
|
|
9784
|
+
}));
|
|
9785
|
+
}
|
|
9786
|
+
}
|
|
9787
|
+
else {
|
|
9788
|
+
this.chatService.scrollToMessage(messageId);
|
|
8986
9789
|
}
|
|
8987
9790
|
}
|
|
8988
9791
|
/**
|
|
@@ -9022,8 +9825,219 @@ class ChatComponent {
|
|
|
9022
9825
|
this.chatService.selectOnMenuClose = false;
|
|
9023
9826
|
}
|
|
9024
9827
|
}
|
|
9828
|
+
/**
|
|
9829
|
+
* @hidden
|
|
9830
|
+
*/
|
|
9831
|
+
onMessageListResize() {
|
|
9832
|
+
this.anchor?.calculateMessageBoxSeparator();
|
|
9833
|
+
const layoutChange = this.chatService.layoutChangeInProgress;
|
|
9834
|
+
const skipAutoScroll = !!this._pendingScrollAction || this._scrollHandledBeforePaint || layoutChange;
|
|
9835
|
+
if (skipAutoScroll) {
|
|
9836
|
+
this._scrollHandledBeforePaint = false;
|
|
9837
|
+
if (layoutChange) {
|
|
9838
|
+
this.chatService.layoutChangeInProgress = false;
|
|
9839
|
+
this.anchor?.onScroll();
|
|
9840
|
+
}
|
|
9841
|
+
return;
|
|
9842
|
+
}
|
|
9843
|
+
this.anchor?.autoScrollToBottom();
|
|
9844
|
+
}
|
|
9845
|
+
/**
|
|
9846
|
+
* Schedules the new-message scroll adjustment on zone.onStable so it runs
|
|
9847
|
+
* after Angular renders the new DOM but before the browser paints,
|
|
9848
|
+
* preventing a visible intermediate frame.
|
|
9849
|
+
*/
|
|
9850
|
+
scheduleNewMessageScroll() {
|
|
9851
|
+
if (!this._pendingScrollAction) {
|
|
9852
|
+
return;
|
|
9853
|
+
}
|
|
9854
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9855
|
+
this.zone.run(() => {
|
|
9856
|
+
const action = this._pendingScrollAction;
|
|
9857
|
+
this._pendingScrollAction = null;
|
|
9858
|
+
this._scrollHandledBeforePaint = true;
|
|
9859
|
+
if (action === 'author') {
|
|
9860
|
+
this._lastNewMessageId = null;
|
|
9861
|
+
this.autoScroll = true;
|
|
9862
|
+
this.anchor?.scrollToBottomWithSettle();
|
|
9863
|
+
return;
|
|
9864
|
+
}
|
|
9865
|
+
if (action === 'receiver') {
|
|
9866
|
+
const messageEl = this.getLastNewMessageElement();
|
|
9867
|
+
this._lastNewMessageId = null;
|
|
9868
|
+
this.autoScroll = true;
|
|
9869
|
+
if (messageEl) {
|
|
9870
|
+
this.anchor?.scrollWithThreshold(messageEl);
|
|
9871
|
+
}
|
|
9872
|
+
else {
|
|
9873
|
+
this.anchor?.scrollToBottom();
|
|
9874
|
+
}
|
|
9875
|
+
}
|
|
9876
|
+
});
|
|
9877
|
+
}));
|
|
9878
|
+
}
|
|
9879
|
+
detectNewMessageScrollAction() {
|
|
9880
|
+
const messages = this.processedMessages;
|
|
9881
|
+
const prevLength = this._previousMessagesLength;
|
|
9882
|
+
const hasNoMessages = !messages;
|
|
9883
|
+
const hasNoNewMessages = messages && messages.length <= prevLength;
|
|
9884
|
+
const isInitialLoad = prevLength === 0 && !this._hasProcessedMessages;
|
|
9885
|
+
const lastMessage = messages?.length > 0 ? messages[messages.length - 1] : null;
|
|
9886
|
+
const currentLastId = lastMessage?.id ?? null;
|
|
9887
|
+
const isLastMessageReplaced = messages?.length === prevLength
|
|
9888
|
+
&& currentLastId !== this._previousLastMessageId
|
|
9889
|
+
&& this._previousLastMessageId !== null && currentLastId !== null;
|
|
9890
|
+
if (hasNoMessages || (hasNoNewMessages && !isLastMessageReplaced) || isInitialLoad) {
|
|
9891
|
+
this._pendingScrollAction = null;
|
|
9892
|
+
this._lastNewMessageId = null;
|
|
9893
|
+
return;
|
|
9894
|
+
}
|
|
9895
|
+
this._lastNewMessageId = currentLastId;
|
|
9896
|
+
const isAuthor = this.isOwnMessage(lastMessage);
|
|
9897
|
+
if (isAuthor) {
|
|
9898
|
+
this._pendingScrollAction = 'author';
|
|
9899
|
+
return;
|
|
9900
|
+
}
|
|
9901
|
+
if (!this.anchor) {
|
|
9902
|
+
this._pendingScrollAction = null;
|
|
9903
|
+
return;
|
|
9904
|
+
}
|
|
9905
|
+
const distance = this.anchor.getDistanceFromBottom();
|
|
9906
|
+
const threshold = this.anchor.getAutoScrollThresholdPx();
|
|
9907
|
+
const isNearBottom = distance <= Math.max(threshold, scrollButtonThreshold);
|
|
9908
|
+
this._pendingScrollAction = isNearBottom ? 'receiver' : null;
|
|
9909
|
+
}
|
|
9910
|
+
getLastNewMessageElement() {
|
|
9911
|
+
if (this._lastNewMessageId == null) {
|
|
9912
|
+
return null;
|
|
9913
|
+
}
|
|
9914
|
+
const ref = this.chatService.messageElementsMap.get(this._lastNewMessageId);
|
|
9915
|
+
return ref?.nativeElement ?? null;
|
|
9916
|
+
}
|
|
9025
9917
|
findLastPinnedMessage() {
|
|
9026
|
-
|
|
9918
|
+
const fromMessages = [...this.processedMessages].reverse().find((message) => message.isPinned);
|
|
9919
|
+
if (fromMessages) {
|
|
9920
|
+
return fromMessages;
|
|
9921
|
+
}
|
|
9922
|
+
if (this.isRemoteMode && this.pinnedMessages?.length) {
|
|
9923
|
+
return [...this.pinnedMessages].reverse().find((message) => message.isPinned);
|
|
9924
|
+
}
|
|
9925
|
+
return undefined;
|
|
9926
|
+
}
|
|
9927
|
+
initEndlessScroll() {
|
|
9928
|
+
if (this.scrollMode === 'endless') {
|
|
9929
|
+
if (this.isRemoteMode) {
|
|
9930
|
+
this.endlessState.syncFromInputs(this.startIndex ?? 0, this.endIndex ?? 0, this.total ?? 0);
|
|
9931
|
+
}
|
|
9932
|
+
else {
|
|
9933
|
+
this.endlessState.init(this.processedMessages?.length || 0, this.pageSize);
|
|
9934
|
+
}
|
|
9935
|
+
this._previousMessagesLength = this.processedMessages?.length || 0;
|
|
9936
|
+
}
|
|
9937
|
+
else {
|
|
9938
|
+
this.endlessState.reset();
|
|
9939
|
+
this._remoteScrollToBottom = false;
|
|
9940
|
+
this._pendingRemoteScrollToMessageId = null;
|
|
9941
|
+
}
|
|
9942
|
+
}
|
|
9943
|
+
handleMessagesChange() {
|
|
9944
|
+
if (this.scrollMode !== 'endless') {
|
|
9945
|
+
const msgs = this.processedMessages;
|
|
9946
|
+
this._previousMessagesLength = msgs?.length || 0;
|
|
9947
|
+
this._previousLastMessageId = msgs?.length > 0 ? msgs[msgs.length - 1]?.id ?? null : null;
|
|
9948
|
+
this._hasProcessedMessages = true;
|
|
9949
|
+
return;
|
|
9950
|
+
}
|
|
9951
|
+
const allMessages = this.processedMessages || [];
|
|
9952
|
+
const wasAtEnd = this.endlessState.isAtEnd;
|
|
9953
|
+
const isNewMessageAppended = allMessages.length > this._previousMessagesLength && this._previousMessagesLength > 0;
|
|
9954
|
+
const isSameLength = allMessages.length === this._previousMessagesLength;
|
|
9955
|
+
const shouldScroll = this._pendingScrollAction !== null;
|
|
9956
|
+
if (isNewMessageAppended) {
|
|
9957
|
+
this.endlessState.updateTotal(allMessages.length);
|
|
9958
|
+
if (shouldScroll) {
|
|
9959
|
+
if (!wasAtEnd) {
|
|
9960
|
+
const range = this.endlessState.jumpToEnd();
|
|
9961
|
+
this.loadMore.emit({ startIndex: range.start, endIndex: range.end });
|
|
9962
|
+
}
|
|
9963
|
+
else {
|
|
9964
|
+
this.endlessState.endIndex = allMessages.length;
|
|
9965
|
+
}
|
|
9966
|
+
}
|
|
9967
|
+
}
|
|
9968
|
+
else if (!isSameLength) {
|
|
9969
|
+
this.endlessState.init(allMessages.length, this.pageSize);
|
|
9970
|
+
}
|
|
9971
|
+
this._previousMessagesLength = allMessages.length;
|
|
9972
|
+
this._previousLastMessageId = allMessages.length > 0 ? allMessages[allMessages.length - 1]?.id ?? null : null;
|
|
9973
|
+
this._hasProcessedMessages = true;
|
|
9974
|
+
}
|
|
9975
|
+
handleRemoteMessagesChange() {
|
|
9976
|
+
const wasLoading = this.endlessState.isLoading;
|
|
9977
|
+
const prevLength = this._previousMessagesLength;
|
|
9978
|
+
const currentLength = this.processedMessages?.length || 0;
|
|
9979
|
+
const isInitialBatch = prevLength === 0 && currentLength > 0;
|
|
9980
|
+
if (wasLoading) {
|
|
9981
|
+
this.endlessState.isLoading = false;
|
|
9982
|
+
if (this._remoteScrollToBottom) {
|
|
9983
|
+
this._remoteScrollToBottom = false;
|
|
9984
|
+
this._scrollHandledBeforePaint = true;
|
|
9985
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9986
|
+
this.anchor?.scrollToBottomWithSettle();
|
|
9987
|
+
}));
|
|
9988
|
+
}
|
|
9989
|
+
else {
|
|
9990
|
+
this._scrollHandledBeforePaint = true;
|
|
9991
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
9992
|
+
this.anchor?.preserveScrollPosition();
|
|
9993
|
+
this.anchor?.setAriaLive('polite');
|
|
9994
|
+
}));
|
|
9995
|
+
}
|
|
9996
|
+
}
|
|
9997
|
+
else if (isInitialBatch && !this._pendingScrollAction) {
|
|
9998
|
+
this.autoScroll = true;
|
|
9999
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
10000
|
+
this.anchor?.scrollToBottom();
|
|
10001
|
+
this.anchor?.calculateMessageBoxSeparator();
|
|
10002
|
+
}));
|
|
10003
|
+
}
|
|
10004
|
+
else if (currentLength > 0 && !this._pendingScrollAction) {
|
|
10005
|
+
const lastMessage = this.processedMessages[currentLength - 1];
|
|
10006
|
+
const isNowAtEnd = this.endIndex >= this.total;
|
|
10007
|
+
if (isNowAtEnd && this.isOwnMessage(lastMessage)) {
|
|
10008
|
+
this._pendingScrollAction = 'author';
|
|
10009
|
+
}
|
|
10010
|
+
}
|
|
10011
|
+
this._previousMessagesLength = currentLength;
|
|
10012
|
+
this._previousLastMessageId = currentLength > 0
|
|
10013
|
+
? this.processedMessages[currentLength - 1]?.id ?? null
|
|
10014
|
+
: null;
|
|
10015
|
+
if (currentLength > 0) {
|
|
10016
|
+
this._hasProcessedMessages = true;
|
|
10017
|
+
}
|
|
10018
|
+
}
|
|
10019
|
+
handleRemoteReferencedMessageClick(messageId) {
|
|
10020
|
+
const messageEl = this.chatService.messageElementsMap.get(messageId);
|
|
10021
|
+
if (messageEl) {
|
|
10022
|
+
this.anchor?.lockForMessageScroll();
|
|
10023
|
+
this.chatService.scrollToMessage(messageId, 'auto');
|
|
10024
|
+
this.anchor?.unlockForMessageScroll();
|
|
10025
|
+
return;
|
|
10026
|
+
}
|
|
10027
|
+
this._pendingRemoteScrollToMessageId = messageId;
|
|
10028
|
+
}
|
|
10029
|
+
handlePendingRemoteScroll() {
|
|
10030
|
+
if (!this._pendingRemoteScrollToMessageId) {
|
|
10031
|
+
return;
|
|
10032
|
+
}
|
|
10033
|
+
const messageId = this._pendingRemoteScrollToMessageId;
|
|
10034
|
+
this._pendingRemoteScrollToMessageId = null;
|
|
10035
|
+
this._scrollHandledBeforePaint = true;
|
|
10036
|
+
this.subs.add(this.zone.onStable.pipe(take(1)).subscribe(() => {
|
|
10037
|
+
this.anchor?.lockForMessageScroll();
|
|
10038
|
+
this.chatService.scrollToMessage(messageId, 'auto');
|
|
10039
|
+
this.anchor?.unlockForMessageScroll();
|
|
10040
|
+
}));
|
|
9027
10041
|
}
|
|
9028
10042
|
updateChatServiceProperties(propNames, changes) {
|
|
9029
10043
|
propNames.forEach(propName => {
|
|
@@ -9032,6 +10046,34 @@ class ChatComponent {
|
|
|
9032
10046
|
}
|
|
9033
10047
|
});
|
|
9034
10048
|
}
|
|
10049
|
+
validateRemoteInputs() {
|
|
10050
|
+
if (!isDevMode()) {
|
|
10051
|
+
return;
|
|
10052
|
+
}
|
|
10053
|
+
const hasRemoteInputs = isPresent(this.total) || isPresent(this.startIndex) || isPresent(this.endIndex);
|
|
10054
|
+
if (hasRemoteInputs && this.scrollMode !== 'endless') {
|
|
10055
|
+
console.warn('[kendo-chat] [total], [startIndex], and [endIndex] are only used when [scrollMode] is \'endless\'.');
|
|
10056
|
+
return;
|
|
10057
|
+
}
|
|
10058
|
+
if (isPresent(this.total) && (!isPresent(this.startIndex) || !isPresent(this.endIndex))) {
|
|
10059
|
+
console.warn('[kendo-chat] Remote mode requires [startIndex] and [endIndex] when [total] is set.');
|
|
10060
|
+
}
|
|
10061
|
+
if (isPresent(this.startIndex) && this.startIndex < 0) {
|
|
10062
|
+
console.warn('[kendo-chat] [startIndex] must not be negative.');
|
|
10063
|
+
}
|
|
10064
|
+
if (isPresent(this.startIndex) && isPresent(this.endIndex) && this.startIndex > this.endIndex) {
|
|
10065
|
+
console.warn(`[kendo-chat] [startIndex] (${this.startIndex}) must not exceed [endIndex] (${this.endIndex}).`);
|
|
10066
|
+
}
|
|
10067
|
+
if (isPresent(this.endIndex) && isPresent(this.total) && this.endIndex > this.total) {
|
|
10068
|
+
console.warn(`[kendo-chat] [endIndex] (${this.endIndex}) must not exceed [total] (${this.total}).`);
|
|
10069
|
+
}
|
|
10070
|
+
if (isPresent(this.startIndex) && isPresent(this.endIndex) && this.messages) {
|
|
10071
|
+
const expectedLength = this.endIndex - this.startIndex;
|
|
10072
|
+
if (this.messages.length !== expectedLength) {
|
|
10073
|
+
console.warn(`[kendo-chat] messages.length (${this.messages.length}) does not match the range [startIndex]–[endIndex] (expected ${expectedLength}).`);
|
|
10074
|
+
}
|
|
10075
|
+
}
|
|
10076
|
+
}
|
|
9035
10077
|
mergeWithDefaultActions(actions, defaultActions) {
|
|
9036
10078
|
if (!actions || actions.length === 0) {
|
|
9037
10079
|
return [];
|
|
@@ -9045,7 +10087,7 @@ class ChatComponent {
|
|
|
9045
10087
|
});
|
|
9046
10088
|
}
|
|
9047
10089
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatComponent, deps: [{ token: i1.LocalizationService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: ChatService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9048
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ChatComponent, isStandalone: true, selector: "kendo-chat", inputs: { messages: "messages", authorId: "authorId", messageBoxType: "messageBoxType", height: "height", width: "width", placeholder: "placeholder", messageWidthMode: "messageWidthMode", timestampVisibility: "timestampVisibility", showUsername: "showUsername", showAvatar: "showAvatar", allowMessageCollapse: "allowMessageCollapse", speechToTextButton: "speechToTextButton", fileSelectButton: "fileSelectButton", messageBoxSettings: "messageBoxSettings", messageToolbarActions: "messageToolbarActions", inputValue: "inputValue", authorMessageSettings: "authorMessageSettings", receiverMessageSettings: "receiverMessageSettings", messageContextMenuActions: "messageContextMenuActions", fileActions: "fileActions", messageFilesLayout: "messageFilesLayout", suggestionsLayout: "suggestionsLayout", quickActionsLayout: "quickActionsLayout", suggestions: "suggestions", sendButton: "sendButton", sendButtonSettings: "sendButtonSettings", modelFields: "modelFields", scrollToBottomButton: "scrollToBottomButton", loading: "loading" }, outputs: { sendMessage: "sendMessage", resendMessage: "resendMessage", toolbarActionClick: "toolbarActionClick", contextMenuActionClick: "contextMenuActionClick", fileActionClick: "fileActionClick", download: "download", executeAction: "executeAction", suggestionExecute: "suggestionExecute", fileSelect: "fileSelect", fileRemove: "fileRemove", unpin: "unpin", inputValueChange: "inputValueChange" }, host: { properties: { "class": "this.className", "attr.dir": "this.dirAttr" } }, providers: [
|
|
10090
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ChatComponent, isStandalone: true, selector: "kendo-chat", inputs: { messages: "messages", authorId: "authorId", messageBoxType: "messageBoxType", height: "height", width: "width", placeholder: "placeholder", messageWidthMode: "messageWidthMode", timestampVisibility: "timestampVisibility", showUsername: "showUsername", showAvatar: "showAvatar", allowMessageCollapse: "allowMessageCollapse", speechToTextButton: "speechToTextButton", fileSelectButton: "fileSelectButton", messageBoxSettings: "messageBoxSettings", messageToolbarActions: "messageToolbarActions", inputValue: "inputValue", authorMessageSettings: "authorMessageSettings", receiverMessageSettings: "receiverMessageSettings", messageContextMenuActions: "messageContextMenuActions", fileActions: "fileActions", messageFilesLayout: "messageFilesLayout", suggestionsLayout: "suggestionsLayout", quickActionsLayout: "quickActionsLayout", suggestions: "suggestions", sendButton: "sendButton", sendButtonSettings: "sendButtonSettings", scrollMode: "scrollMode", pageSize: "pageSize", autoScrollThreshold: "autoScrollThreshold", total: "total", startIndex: "startIndex", endIndex: "endIndex", pinnedMessages: "pinnedMessages", repliedToMessages: "repliedToMessages", modelFields: "modelFields", scrollToBottomButton: "scrollToBottomButton", loading: "loading" }, outputs: { sendMessage: "sendMessage", resendMessage: "resendMessage", toolbarActionClick: "toolbarActionClick", contextMenuActionClick: "contextMenuActionClick", fileActionClick: "fileActionClick", download: "download", executeAction: "executeAction", suggestionExecute: "suggestionExecute", fileSelect: "fileSelect", fileRemove: "fileRemove", unpin: "unpin", inputValueChange: "inputValueChange", loadMore: "loadMore", referencedMessageClick: "referencedMessageClick" }, host: { properties: { "class": "this.className", "attr.dir": "this.dirAttr" } }, providers: [
|
|
9049
10091
|
LocalizationService,
|
|
9050
10092
|
ChatService,
|
|
9051
10093
|
SuggestionsScrollService,
|
|
@@ -9053,7 +10095,7 @@ class ChatComponent {
|
|
|
9053
10095
|
provide: L10N_PREFIX,
|
|
9054
10096
|
useValue: 'kendo.chat',
|
|
9055
10097
|
},
|
|
9056
|
-
], queries: [{ propertyName: "attachmentTemplate", first: true, predicate: AttachmentTemplateDirective, descendants: true }, { propertyName: "chatHeaderTemplate", first: true, predicate: ChatHeaderTemplateDirective, descendants: true }, { propertyName: "chatNoDataTemplate", first: true, predicate: NoDataTemplateDirective, descendants: true }, { propertyName: "authorMessageContentTemplate", first: true, predicate: AuthorMessageContentTemplateDirective, descendants: true }, { propertyName: "receiverMessageContentTemplate", first: true, predicate: ReceiverMessageContentTemplateDirective, descendants: true }, { propertyName: "messageContentTemplate", first: true, predicate: MessageContentTemplateDirective, descendants: true }, { propertyName: "authorMessageTemplate", first: true, predicate: AuthorMessageTemplateDirective, descendants: true }, { propertyName: "receiverMessageTemplate", first: true, predicate: ReceiverMessageTemplateDirective, descendants: true }, { propertyName: "messageTemplate", first: true, predicate: MessageTemplateDirective, descendants: true }, { propertyName: "timestampTemplate", first: true, predicate: ChatTimestampTemplateDirective, descendants: true }, { propertyName: "suggestionTemplate", first: true, predicate: ChatSuggestionTemplateDirective, descendants: true }, { propertyName: "statusTemplate", first: true, predicate: ChatStatusTemplateDirective, descendants: true }, { propertyName: "messageBoxTemplate", first: true, predicate: ChatMessageBoxTemplateDirective, descendants: true }, { propertyName: "messageBoxStartAffixTemplate", first: true, predicate: ChatMessageBoxStartAffixTemplateDirective, descendants: true }, { propertyName: "messageBoxEndAffixTemplate", first: true, predicate: ChatMessageBoxEndAffixTemplateDirective, descendants: true }, { propertyName: "messageBoxTopAffixTemplate", first: true, predicate: ChatMessageBoxTopAffixTemplateDirective, descendants: true }, { propertyName: "userStatusTemplate", first: true, predicate: ChatUserStatusTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "messagesContextMenu", first: true, predicate: ["messagesContextMenu"], descendants: true }, { propertyName: "messageBox", first: true, predicate: ["messageBox"], descendants: true }, { propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
10098
|
+
], queries: [{ propertyName: "attachmentTemplate", first: true, predicate: AttachmentTemplateDirective, descendants: true }, { propertyName: "chatHeaderTemplate", first: true, predicate: ChatHeaderTemplateDirective, descendants: true }, { propertyName: "chatNoDataTemplate", first: true, predicate: NoDataTemplateDirective, descendants: true }, { propertyName: "authorMessageContentTemplate", first: true, predicate: AuthorMessageContentTemplateDirective, descendants: true }, { propertyName: "receiverMessageContentTemplate", first: true, predicate: ReceiverMessageContentTemplateDirective, descendants: true }, { propertyName: "messageContentTemplate", first: true, predicate: MessageContentTemplateDirective, descendants: true }, { propertyName: "authorMessageTemplate", first: true, predicate: AuthorMessageTemplateDirective, descendants: true }, { propertyName: "receiverMessageTemplate", first: true, predicate: ReceiverMessageTemplateDirective, descendants: true }, { propertyName: "messageTemplate", first: true, predicate: MessageTemplateDirective, descendants: true }, { propertyName: "timestampTemplate", first: true, predicate: ChatTimestampTemplateDirective, descendants: true }, { propertyName: "suggestionTemplate", first: true, predicate: ChatSuggestionTemplateDirective, descendants: true }, { propertyName: "statusTemplate", first: true, predicate: ChatStatusTemplateDirective, descendants: true }, { propertyName: "messageBoxTemplate", first: true, predicate: ChatMessageBoxTemplateDirective, descendants: true }, { propertyName: "messageBoxStartAffixTemplate", first: true, predicate: ChatMessageBoxStartAffixTemplateDirective, descendants: true }, { propertyName: "messageBoxEndAffixTemplate", first: true, predicate: ChatMessageBoxEndAffixTemplateDirective, descendants: true }, { propertyName: "messageBoxTopAffixTemplate", first: true, predicate: ChatMessageBoxTopAffixTemplateDirective, descendants: true }, { propertyName: "userStatusTemplate", first: true, predicate: ChatUserStatusTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "messagesContextMenu", first: true, predicate: ["messagesContextMenu"], descendants: true }, { propertyName: "messageBox", first: true, predicate: ["messageBox"], descendants: true }, { propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "anchor", first: true, predicate: ["anchor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
9057
10099
|
<ng-container
|
|
9058
10100
|
kendoChatLocalizedMessages
|
|
9059
10101
|
i18n-deletedMessageSenderText="
|
|
@@ -9123,9 +10165,7 @@ class ChatComponent {
|
|
|
9123
10165
|
kendo.chat.nextSuggestionsButtonTitle|The title of the button that scrolls to the next suggestions
|
|
9124
10166
|
"
|
|
9125
10167
|
nextSuggestionsButtonTitle="Scroll right"
|
|
9126
|
-
i18n-unpinMessageTitle="
|
|
9127
|
-
kendo.chat.unpinMessageTitle|The title of the button that unpins a pinned message
|
|
9128
|
-
"
|
|
10168
|
+
i18n-unpinMessageTitle="kendo.chat.unpinMessageTitle|The title of the button that unpins a pinned message"
|
|
9129
10169
|
unpinMessageTitle="Unpin message"
|
|
9130
10170
|
>
|
|
9131
10171
|
</ng-container>
|
|
@@ -9144,18 +10184,31 @@ class ChatComponent {
|
|
|
9144
10184
|
[attr.aria-label]="textFor('messageListLabel')"
|
|
9145
10185
|
#anchor="scrollAnchor"
|
|
9146
10186
|
[(autoScroll)]="autoScroll"
|
|
10187
|
+
[autoScrollThreshold]="autoScrollThreshold"
|
|
10188
|
+
[endlessMode]="scrollMode === 'endless'"
|
|
10189
|
+
[rangeIsAtEnd]="endlessState.isAtEnd"
|
|
10190
|
+
(nearTop)="onNearTop()"
|
|
10191
|
+
(nearBottom)="onNearBottom()"
|
|
9147
10192
|
>
|
|
9148
10193
|
@if (pinnedMessage) {
|
|
9149
10194
|
<div
|
|
9150
10195
|
class="k-message-reference k-message-pinned"
|
|
9151
10196
|
[class.k-message-reference-receiver]="!isOwnMessage(pinnedMessage)"
|
|
9152
10197
|
[class.k-message-reference-sender]="isOwnMessage(pinnedMessage)"
|
|
9153
|
-
(click)="scrollToPinnedMessage()"
|
|
10198
|
+
(click)="scrollToPinnedMessage($event)"
|
|
9154
10199
|
>
|
|
9155
10200
|
<kendo-icon-wrapper name="pin" [svgIcon]="pinIcon"> </kendo-icon-wrapper>
|
|
9156
10201
|
<chat-message-reference-content [message]="pinnedMessage"></chat-message-reference-content>
|
|
9157
10202
|
<span class="k-spacer"></span>
|
|
9158
|
-
<button
|
|
10203
|
+
<button
|
|
10204
|
+
kendoButton
|
|
10205
|
+
icon="x"
|
|
10206
|
+
[svgIcon]="deleteIcon"
|
|
10207
|
+
[attr.title]="textFor('unpinMessageTitle')"
|
|
10208
|
+
(click)="unpin.emit(pinnedMessage)"
|
|
10209
|
+
fillMode="flat"
|
|
10210
|
+
size="xsmall"
|
|
10211
|
+
></button>
|
|
9159
10212
|
</div>
|
|
9160
10213
|
} @if (processedMessages && processedMessages.length === 0) {
|
|
9161
10214
|
<div class="k-message-list-content k-message-list-content-empty">
|
|
@@ -9163,7 +10216,7 @@ class ChatComponent {
|
|
|
9163
10216
|
</div>
|
|
9164
10217
|
} @else {
|
|
9165
10218
|
<kendo-chat-message-list
|
|
9166
|
-
[messages]="
|
|
10219
|
+
[messages]="renderedMessages"
|
|
9167
10220
|
[authorMessageContentTemplate]="authorMessageContentTemplate"
|
|
9168
10221
|
[receiverMessageContentTemplate]="receiverMessageContentTemplate"
|
|
9169
10222
|
[messageContentTemplate]="messageContentTemplate"
|
|
@@ -9177,7 +10230,7 @@ class ChatComponent {
|
|
|
9177
10230
|
[attachmentTemplate]="attachmentTemplate"
|
|
9178
10231
|
[authorId]="authorId"
|
|
9179
10232
|
(executeAction)="dispatchAction($event)"
|
|
9180
|
-
(resize)="
|
|
10233
|
+
(resize)="onMessageListResize()"
|
|
9181
10234
|
(navigate)="this.autoScroll = false"
|
|
9182
10235
|
>
|
|
9183
10236
|
</kendo-chat-message-list>
|
|
@@ -9186,11 +10239,11 @@ class ChatComponent {
|
|
|
9186
10239
|
<kendo-floatingactionbutton
|
|
9187
10240
|
positionMode="absolute"
|
|
9188
10241
|
[size]="'small'"
|
|
9189
|
-
[themeColor]="'
|
|
10242
|
+
[themeColor]="'base'"
|
|
9190
10243
|
[align]="{ horizontal: 'center' }"
|
|
9191
10244
|
icon="arrow-down-outline"
|
|
9192
10245
|
[svgIcon]="scrollToBottomIcon"
|
|
9193
|
-
(click)="
|
|
10246
|
+
(click)="onScrollToBottomClick()"
|
|
9194
10247
|
></kendo-floatingactionbutton>
|
|
9195
10248
|
</div>
|
|
9196
10249
|
}
|
|
@@ -9227,7 +10280,11 @@ class ChatComponent {
|
|
|
9227
10280
|
(popupClose)="handleMenuClose($event)"
|
|
9228
10281
|
(select)="onContextMenuAction($event.item.originalAction)"
|
|
9229
10282
|
></kendo-contextmenu>
|
|
9230
|
-
|
|
10283
|
+
|
|
10284
|
+
@if (showLicenseWatermark) {
|
|
10285
|
+
<div kendoWatermarkOverlay [licenseMessage]="licenseMessage"></div>
|
|
10286
|
+
}
|
|
10287
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective$2, selector: "[kendoChatLocalizedMessages]" }, { kind: "directive", type: ScrollAnchorDirective, selector: "[kendoChatScrollAnchor]", inputs: ["autoScroll", "autoScrollThreshold", "endlessMode", "rangeIsAtEnd"], outputs: ["autoScrollChange", "nearTop", "nearBottom"], exportAs: ["scrollAnchor"] }, { kind: "component", type: MessageListComponent, selector: "kendo-chat-message-list", inputs: ["messages", "attachmentTemplate", "authorMessageContentTemplate", "receiverMessageContentTemplate", "messageContentTemplate", "authorMessageTemplate", "receiverMessageTemplate", "messageTemplate", "timestampTemplate", "statusTemplate", "userStatusTemplate", "localization", "authorId"], outputs: ["executeAction", "navigate", "resize"] }, { kind: "component", type: MessageBoxComponent, selector: "kendo-message-box", inputs: ["authorId", "autoScroll", "suggestions", "placeholder", "inputValue", "localization", "messageBoxTemplate", "messageBoxStartAffixTemplate", "messageBoxEndAffixTemplate", "messageBoxTopAffixTemplate", "suggestionTemplate", "loading"], outputs: ["sendMessage", "executeSuggestion", "fileSelect", "fileRemove"] }, { kind: "component", type: MessageReferenceComponent, selector: "chat-message-reference-content", inputs: ["message"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: ContextMenuComponent, selector: "kendo-contextmenu", inputs: ["showOn", "target", "filter", "alignToAnchor", "vertical", "popupAnimate", "popupAlign", "anchorAlign", "collision", "appendTo", "ariaLabel"], outputs: ["popupOpen", "popupClose", "select", "open", "close"], exportAs: ["kendoContextMenu"] }, { kind: "component", type: FloatingActionButtonComponent, selector: "kendo-floatingactionbutton", inputs: ["themeColor", "size", "rounded", "disabled", "align", "offset", "positionMode", "icon", "svgIcon", "iconClass", "buttonClass", "dialClass", "text", "dialItemAnimation", "tabIndex", "dialItems"], outputs: ["blur", "focus", "dialItemClick", "open", "close"] }, { kind: "component", type: WatermarkOverlayComponent, selector: "div[kendoWatermarkOverlay], kendo-watermark-overlay", inputs: ["licenseMessage"] }] });
|
|
9231
10288
|
}
|
|
9232
10289
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatComponent, decorators: [{
|
|
9233
10290
|
type: Component,
|
|
@@ -9312,9 +10369,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9312
10369
|
kendo.chat.nextSuggestionsButtonTitle|The title of the button that scrolls to the next suggestions
|
|
9313
10370
|
"
|
|
9314
10371
|
nextSuggestionsButtonTitle="Scroll right"
|
|
9315
|
-
i18n-unpinMessageTitle="
|
|
9316
|
-
kendo.chat.unpinMessageTitle|The title of the button that unpins a pinned message
|
|
9317
|
-
"
|
|
10372
|
+
i18n-unpinMessageTitle="kendo.chat.unpinMessageTitle|The title of the button that unpins a pinned message"
|
|
9318
10373
|
unpinMessageTitle="Unpin message"
|
|
9319
10374
|
>
|
|
9320
10375
|
</ng-container>
|
|
@@ -9333,18 +10388,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9333
10388
|
[attr.aria-label]="textFor('messageListLabel')"
|
|
9334
10389
|
#anchor="scrollAnchor"
|
|
9335
10390
|
[(autoScroll)]="autoScroll"
|
|
10391
|
+
[autoScrollThreshold]="autoScrollThreshold"
|
|
10392
|
+
[endlessMode]="scrollMode === 'endless'"
|
|
10393
|
+
[rangeIsAtEnd]="endlessState.isAtEnd"
|
|
10394
|
+
(nearTop)="onNearTop()"
|
|
10395
|
+
(nearBottom)="onNearBottom()"
|
|
9336
10396
|
>
|
|
9337
10397
|
@if (pinnedMessage) {
|
|
9338
10398
|
<div
|
|
9339
10399
|
class="k-message-reference k-message-pinned"
|
|
9340
10400
|
[class.k-message-reference-receiver]="!isOwnMessage(pinnedMessage)"
|
|
9341
10401
|
[class.k-message-reference-sender]="isOwnMessage(pinnedMessage)"
|
|
9342
|
-
(click)="scrollToPinnedMessage()"
|
|
10402
|
+
(click)="scrollToPinnedMessage($event)"
|
|
9343
10403
|
>
|
|
9344
10404
|
<kendo-icon-wrapper name="pin" [svgIcon]="pinIcon"> </kendo-icon-wrapper>
|
|
9345
10405
|
<chat-message-reference-content [message]="pinnedMessage"></chat-message-reference-content>
|
|
9346
10406
|
<span class="k-spacer"></span>
|
|
9347
|
-
<button
|
|
10407
|
+
<button
|
|
10408
|
+
kendoButton
|
|
10409
|
+
icon="x"
|
|
10410
|
+
[svgIcon]="deleteIcon"
|
|
10411
|
+
[attr.title]="textFor('unpinMessageTitle')"
|
|
10412
|
+
(click)="unpin.emit(pinnedMessage)"
|
|
10413
|
+
fillMode="flat"
|
|
10414
|
+
size="xsmall"
|
|
10415
|
+
></button>
|
|
9348
10416
|
</div>
|
|
9349
10417
|
} @if (processedMessages && processedMessages.length === 0) {
|
|
9350
10418
|
<div class="k-message-list-content k-message-list-content-empty">
|
|
@@ -9352,7 +10420,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9352
10420
|
</div>
|
|
9353
10421
|
} @else {
|
|
9354
10422
|
<kendo-chat-message-list
|
|
9355
|
-
[messages]="
|
|
10423
|
+
[messages]="renderedMessages"
|
|
9356
10424
|
[authorMessageContentTemplate]="authorMessageContentTemplate"
|
|
9357
10425
|
[receiverMessageContentTemplate]="receiverMessageContentTemplate"
|
|
9358
10426
|
[messageContentTemplate]="messageContentTemplate"
|
|
@@ -9366,7 +10434,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9366
10434
|
[attachmentTemplate]="attachmentTemplate"
|
|
9367
10435
|
[authorId]="authorId"
|
|
9368
10436
|
(executeAction)="dispatchAction($event)"
|
|
9369
|
-
(resize)="
|
|
10437
|
+
(resize)="onMessageListResize()"
|
|
9370
10438
|
(navigate)="this.autoScroll = false"
|
|
9371
10439
|
>
|
|
9372
10440
|
</kendo-chat-message-list>
|
|
@@ -9375,11 +10443,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9375
10443
|
<kendo-floatingactionbutton
|
|
9376
10444
|
positionMode="absolute"
|
|
9377
10445
|
[size]="'small'"
|
|
9378
|
-
[themeColor]="'
|
|
10446
|
+
[themeColor]="'base'"
|
|
9379
10447
|
[align]="{ horizontal: 'center' }"
|
|
9380
10448
|
icon="arrow-down-outline"
|
|
9381
10449
|
[svgIcon]="scrollToBottomIcon"
|
|
9382
|
-
(click)="
|
|
10450
|
+
(click)="onScrollToBottomClick()"
|
|
9383
10451
|
></kendo-floatingactionbutton>
|
|
9384
10452
|
</div>
|
|
9385
10453
|
}
|
|
@@ -9416,6 +10484,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9416
10484
|
(popupClose)="handleMenuClose($event)"
|
|
9417
10485
|
(select)="onContextMenuAction($event.item.originalAction)"
|
|
9418
10486
|
></kendo-contextmenu>
|
|
10487
|
+
|
|
10488
|
+
@if (showLicenseWatermark) {
|
|
10489
|
+
<div kendoWatermarkOverlay [licenseMessage]="licenseMessage"></div>
|
|
10490
|
+
}
|
|
9419
10491
|
`,
|
|
9420
10492
|
standalone: true,
|
|
9421
10493
|
imports: [
|
|
@@ -9429,6 +10501,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9429
10501
|
ButtonComponent,
|
|
9430
10502
|
ContextMenuComponent,
|
|
9431
10503
|
FloatingActionButtonComponent,
|
|
10504
|
+
WatermarkOverlayComponent,
|
|
9432
10505
|
],
|
|
9433
10506
|
}]
|
|
9434
10507
|
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: ChatService }], propDecorators: { messages: [{
|
|
@@ -9483,6 +10556,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9483
10556
|
type: Input
|
|
9484
10557
|
}], sendButtonSettings: [{
|
|
9485
10558
|
type: Input
|
|
10559
|
+
}], scrollMode: [{
|
|
10560
|
+
type: Input
|
|
10561
|
+
}], pageSize: [{
|
|
10562
|
+
type: Input
|
|
10563
|
+
}], autoScrollThreshold: [{
|
|
10564
|
+
type: Input
|
|
10565
|
+
}], total: [{
|
|
10566
|
+
type: Input
|
|
10567
|
+
}], startIndex: [{
|
|
10568
|
+
type: Input
|
|
10569
|
+
}], endIndex: [{
|
|
10570
|
+
type: Input
|
|
10571
|
+
}], pinnedMessages: [{
|
|
10572
|
+
type: Input
|
|
10573
|
+
}], repliedToMessages: [{
|
|
10574
|
+
type: Input
|
|
9486
10575
|
}], modelFields: [{
|
|
9487
10576
|
type: Input
|
|
9488
10577
|
}], scrollToBottomButton: [{
|
|
@@ -9513,6 +10602,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9513
10602
|
type: Output
|
|
9514
10603
|
}], inputValueChange: [{
|
|
9515
10604
|
type: Output
|
|
10605
|
+
}], loadMore: [{
|
|
10606
|
+
type: Output
|
|
10607
|
+
}], referencedMessageClick: [{
|
|
10608
|
+
type: Output
|
|
9516
10609
|
}], className: [{
|
|
9517
10610
|
type: HostBinding,
|
|
9518
10611
|
args: ['class']
|
|
@@ -9579,6 +10672,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
9579
10672
|
}], messageList: [{
|
|
9580
10673
|
type: ViewChild,
|
|
9581
10674
|
args: ['messageList', { static: true, read: ViewContainerRef }]
|
|
10675
|
+
}], anchor: [{
|
|
10676
|
+
type: ViewChild,
|
|
10677
|
+
args: ['anchor']
|
|
9582
10678
|
}] } });
|
|
9583
10679
|
|
|
9584
10680
|
// eslint-disable no-forward-ref
|
|
@@ -9699,7 +10795,7 @@ class HeroCardComponent {
|
|
|
9699
10795
|
</span>
|
|
9700
10796
|
}
|
|
9701
10797
|
</div>
|
|
9702
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
10798
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
|
|
9703
10799
|
}
|
|
9704
10800
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: HeroCardComponent, decorators: [{
|
|
9705
10801
|
type: Component,
|
|
@@ -9855,8 +10951,8 @@ const defaultOutputActions = [{
|
|
|
9855
10951
|
{
|
|
9856
10952
|
name: 'discard',
|
|
9857
10953
|
type: 'button',
|
|
9858
|
-
icon: 'cancel
|
|
9859
|
-
svgIcon:
|
|
10954
|
+
icon: 'cancel',
|
|
10955
|
+
svgIcon: cancelIcon,
|
|
9860
10956
|
text: 'Discard',
|
|
9861
10957
|
fillMode: 'flat',
|
|
9862
10958
|
}
|
|
@@ -9928,7 +11024,7 @@ class InlineAIPromptContentComponent {
|
|
|
9928
11024
|
calculateMeasurement = calculateMeasurement;
|
|
9929
11025
|
commandMenuIcon = menuIcon;
|
|
9930
11026
|
sendIcon = paperPlaneIcon;
|
|
9931
|
-
stopGenerationIcon =
|
|
11027
|
+
stopGenerationIcon = stopIcon;
|
|
9932
11028
|
isListening = false;
|
|
9933
11029
|
commandMenuItems = [];
|
|
9934
11030
|
messages = {};
|
|
@@ -10185,7 +11281,7 @@ class InlineAIPromptContentComponent {
|
|
|
10185
11281
|
(click)="handlePromptRequest()"
|
|
10186
11282
|
[disabled]="!streaming && (!promptValue?.trim() || isListening)"
|
|
10187
11283
|
[svgIcon]="streaming ? stopGenerationIcon : sendIcon"
|
|
10188
|
-
[icon]="streaming ? 'stop
|
|
11284
|
+
[icon]="streaming ? 'stop' : 'paper-plane'"
|
|
10189
11285
|
></button>
|
|
10190
11286
|
</kendo-textarea-suffix>
|
|
10191
11287
|
</kendo-textarea>
|
|
@@ -10199,7 +11295,7 @@ class InlineAIPromptContentComponent {
|
|
|
10199
11295
|
class="k-hidden"
|
|
10200
11296
|
(select)="onCommandClick($event)">
|
|
10201
11297
|
</kendo-contextmenu>
|
|
10202
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoInlineAIPromptLocalizedMessages]" }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"
|
|
11298
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoInlineAIPromptLocalizedMessages]" }, { kind: "component", type: i2.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: i2.SpeechToTextButtonComponent, selector: "button[kendoSpeechToTextButton]", inputs: ["disabled", "size", "rounded", "fillMode", "themeColor", "integrationMode", "lang", "continuous", "interimResults", "maxAlternatives"], outputs: ["start", "end", "result", "error", "click"], exportAs: ["kendoSpeechToTextButton"] }, { kind: "component", type: i3.TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: i3.TextAreaPrefixComponent, selector: "kendo-textarea-prefix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaPrefix"] }, { kind: "component", type: i3.TextAreaSuffixComponent, selector: "kendo-textarea-suffix", inputs: ["flow", "orientation"], exportAs: ["kendoTextAreaSuffix"] }, { kind: "component", type: i4.ContextMenuComponent, selector: "kendo-contextmenu", inputs: ["showOn", "target", "filter", "alignToAnchor", "vertical", "popupAnimate", "popupAlign", "anchorAlign", "collision", "appendTo", "ariaLabel"], outputs: ["popupOpen", "popupClose", "select", "open", "close"], exportAs: ["kendoContextMenu"] }, { kind: "component", type: i5.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i5.CardActionsComponent, selector: "kendo-card-actions", inputs: ["orientation", "layout", "actions"], outputs: ["action"] }, { kind: "component", type: i5.CardBodyComponent, selector: "kendo-card-body" }] });
|
|
10203
11299
|
}
|
|
10204
11300
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: InlineAIPromptContentComponent, decorators: [{
|
|
10205
11301
|
type: Component,
|
|
@@ -10306,7 +11402,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
10306
11402
|
(click)="handlePromptRequest()"
|
|
10307
11403
|
[disabled]="!streaming && (!promptValue?.trim() || isListening)"
|
|
10308
11404
|
[svgIcon]="streaming ? stopGenerationIcon : sendIcon"
|
|
10309
|
-
[icon]="streaming ? 'stop
|
|
11405
|
+
[icon]="streaming ? 'stop' : 'paper-plane'"
|
|
10310
11406
|
></button>
|
|
10311
11407
|
</kendo-textarea-suffix>
|
|
10312
11408
|
</kendo-textarea>
|
|
@@ -10487,7 +11583,7 @@ class InlineAIPromptComponent {
|
|
|
10487
11583
|
* The default actions are `copy`, `retry`, and `discard`.
|
|
10488
11584
|
* To customize the appearance and order of the default actions, define them with the same `name`.
|
|
10489
11585
|
*
|
|
10490
|
-
* @default [{ name: 'copy', type: 'button', icon: 'copy', svgIcon: copyIcon, text: 'Copy', fillMode: 'flat', themeColor: 'primary', rounded: 'medium'}, { name: 'retry', type: 'button', icon: 'arrow-rotate-cw', svgIcon: arrowRotateCwIcon, text: 'Retry', fillMode: 'flat', themeColor: 'primary', rounded: 'medium'}, { name: 'discard', type: 'button', icon: 'cancel
|
|
11586
|
+
* @default [{ name: 'copy', type: 'button', icon: 'copy', svgIcon: copyIcon, text: 'Copy', fillMode: 'flat', themeColor: 'primary', rounded: 'medium'}, { name: 'retry', type: 'button', icon: 'arrow-rotate-cw', svgIcon: arrowRotateCwIcon, text: 'Retry', fillMode: 'flat', themeColor: 'primary', rounded: 'medium'}, { name: 'discard', type: 'button', icon: 'cancel', svgIcon: cancelIcon, text: 'Discard', fillMode: 'flat', themeColor: 'base', rounded: 'medium'}]
|
|
10491
11587
|
*/
|
|
10492
11588
|
outputActions = defaultOutputActions;
|
|
10493
11589
|
/**
|