@progress/kendo-angular-conversational-ui
Version:
Kendo UI for Angular Conversational UI components
256 lines (255 loc) • 10.7 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Component, ElementRef, forwardRef, HostBinding, Input, NgZone, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { NgIf, NgFor } from '@angular/common';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { Keys } from '@progress/kendo-angular-common';
import { chevronLeftIcon, chevronRightIcon } from '@progress/kendo-svg-icons';
import { LocalizationService } from '@progress/kendo-angular-l10n';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import { ChatItem } from './chat-item';
import { AttachmentTemplateDirective } from './attachment-template.directive';
import { AttachmentComponent } from './attachment.component';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-l10n";
// eslint-disable no-forward-ref
/**
* @hidden
*/
export class MessageAttachmentsComponent extends ChatItem {
zone;
localizationService;
/**
* @hidden
*/
chevronLeftIcon = chevronLeftIcon;
/**
* @hidden
*/
chevronRightIcon = chevronRightIcon;
attachments;
layout;
tabbable;
template;
localization;
get carousel() {
return this.layout !== 'list';
}
deck;
items;
scrollPosition = 0;
selectedIndex = 0;
scrollSubscription;
direction;
get showLeftArrow() {
return this.carousel && this.direction === 'rtl' ? this.scrollPosition > -1 : this.scrollPosition > 0;
}
get showRightArrow() {
return this.carousel && this.direction === 'rtl' ? this.scrollPosition < 0 : this.scrollPosition < 1;
}
carouselKeyHandlers = {
[Keys.ArrowLeft]: (e) => this.navigateTo(e, this.direction === 'rtl' ? 1 : -1),
[Keys.ArrowRight]: (e) => this.navigateTo(e, this.direction === 'rtl' ? -1 : 1)
};
listKeyHandlers = {
[Keys.ArrowUp]: (e) => this.navigateTo(e, -1),
[Keys.ArrowDown]: (e) => this.navigateTo(e, 1)
};
constructor(zone, localizationService) {
super();
this.zone = zone;
this.localizationService = localizationService;
this.direction = this.localizationService.rtl ? 'rtl' : 'ltr';
}
ngAfterViewInit() {
this.zone.runOutsideAngular(() => {
const scrollDebounceTime = 100;
this.scrollSubscription = fromEvent(this.deck.nativeElement, 'scroll')
.pipe(debounceTime(scrollDebounceTime))
.subscribe(() => this.onScroll());
});
}
ngOnDestroy() {
this.scrollSubscription.unsubscribe();
}
isSelected(index) {
return this.selectedIndex === index;
}
itemKeydown(e, attachment) {
const keyHandlers = this.layout === 'list' ?
this.listKeyHandlers : this.carouselKeyHandlers;
const handler = keyHandlers[e.keyCode];
if (handler) {
handler(e, attachment);
}
}
itemClick(index) {
this.select(index);
}
focus() {
this.select(this.selectedIndex);
}
scrollTo(dir) {
const el = this.deck.nativeElement;
const scrollStep = el.scrollWidth / this.items.length;
const max = el.scrollWidth - el.offsetWidth;
const pos = el.scrollLeft + scrollStep * dir;
el.scrollLeft = this.direction === 'rtl' ? Math.min(0, max, pos) : Math.max(0, Math.min(max, pos));
}
select(index) {
this.selectedIndex = index;
const item = this.items.toArray()[index];
if (item) {
item.nativeElement.focus();
}
}
navigateTo(e, offset) {
const prevIndex = this.selectedIndex;
const nextIndex = Math.max(0, Math.min(prevIndex + offset, this.items.length - 1));
if (nextIndex !== prevIndex) {
this.select(nextIndex);
e.preventDefault();
}
}
onScroll() {
const el = this.deck.nativeElement;
if (el.scrollWidth === 0) {
return;
}
const pos = el.scrollLeft / (el.scrollWidth - el.offsetWidth);
if (pos !== this.scrollPosition) {
this.zone.run(() => {
this.scrollPosition = pos;
});
}
}
/**
* @hidden
*/
textFor(key) {
return this.localization.get(key);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageAttachmentsComponent, deps: [{ token: i0.NgZone }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: MessageAttachmentsComponent, isStandalone: true, selector: "kendo-chat-message-attachments", inputs: { attachments: "attachments", layout: "layout", tabbable: "tabbable", template: "template", localization: "localization" }, host: { properties: { "class.k-card-deck-scrollwrap": "this.carousel" } }, providers: [{
provide: ChatItem,
useExisting: forwardRef(() => MessageAttachmentsComponent)
}], viewQueries: [{ propertyName: "deck", first: true, predicate: ["deck"], descendants: true, read: ElementRef, static: true }, { propertyName: "items", predicate: ["item"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: `
<button
*ngIf="showLeftArrow"
(click)="scrollTo(-1)"
kendoButton
tabindex="-1"
[attr.title]="textFor('messageAttachmentLeftArrow')"
[svgIcon]="chevronLeftIcon"
icon="chevron-left"
>
</button>
<div
#deck
[class.k-card-deck]="carousel"
[class.k-card-list]="!carousel"
>
<kendo-chat-attachment #item
*ngFor="let att of attachments; index as index; first as first; last as last"
[attachment]="att"
[template]="template"
[class.k-selected]="isSelected(index)"
[class.k-focus]="isSelected(index)"
[class.k-card-wrap]="true"
[class.k-first]="first"
[class.k-last]="last"
[attr.tabindex]="tabbable && isSelected(index) ? '0' : '-1'"
(click)="itemClick(index)"
(keydown)="itemKeydown($event, att)"
>
</kendo-chat-attachment>
</div>
<button
*ngIf="showRightArrow"
(click)="scrollTo(1)"
kendoButton
tabindex="-1"
[attr.title]="textFor('messageAttachmentRightArrow')"
[svgIcon]="chevronRightIcon"
icon="chevron-right"
>
</button>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: AttachmentComponent, selector: "kendo-chat-attachment", inputs: ["attachment", "template"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MessageAttachmentsComponent, decorators: [{
type: Component,
args: [{
providers: [{
provide: ChatItem,
useExisting: forwardRef(() => MessageAttachmentsComponent)
}],
selector: 'kendo-chat-message-attachments',
template: `
<button
*ngIf="showLeftArrow"
(click)="scrollTo(-1)"
kendoButton
tabindex="-1"
[attr.title]="textFor('messageAttachmentLeftArrow')"
[svgIcon]="chevronLeftIcon"
icon="chevron-left"
>
</button>
<div
#deck
[class.k-card-deck]="carousel"
[class.k-card-list]="!carousel"
>
<kendo-chat-attachment #item
*ngFor="let att of attachments; index as index; first as first; last as last"
[attachment]="att"
[template]="template"
[class.k-selected]="isSelected(index)"
[class.k-focus]="isSelected(index)"
[class.k-card-wrap]="true"
[class.k-first]="first"
[class.k-last]="last"
[attr.tabindex]="tabbable && isSelected(index) ? '0' : '-1'"
(click)="itemClick(index)"
(keydown)="itemKeydown($event, att)"
>
</kendo-chat-attachment>
</div>
<button
*ngIf="showRightArrow"
(click)="scrollTo(1)"
kendoButton
tabindex="-1"
[attr.title]="textFor('messageAttachmentRightArrow')"
[svgIcon]="chevronRightIcon"
icon="chevron-right"
>
</button>
`,
standalone: true,
imports: [NgIf, ButtonComponent, NgFor, AttachmentComponent]
}]
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i1.LocalizationService }]; }, propDecorators: { attachments: [{
type: Input
}], layout: [{
type: Input
}], tabbable: [{
type: Input
}], template: [{
type: Input
}], localization: [{
type: Input
}], carousel: [{
type: HostBinding,
args: ['class.k-card-deck-scrollwrap']
}], deck: [{
type: ViewChild,
args: ['deck', { read: ElementRef, static: true }]
}], items: [{
type: ViewChildren,
args: ['item', { read: ElementRef }]
}] } });