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