UNPKG

@progress/kendo-angular-conversational-ui

Version:

Kendo UI for Angular Conversational UI components

256 lines (255 loc) 10.7 kB
/**----------------------------------------------------------------------------------------- * 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 }] }] } });