UNPKG

@progress/kendo-angular-layout

Version:

Kendo UI for Angular Layout Package - a collection of components to create professional application layoyts

773 lines (772 loc) 36 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { ChangeDetectorRef, Component, ElementRef, Input, NgZone, QueryList, Renderer2, ViewChild, ViewChildren, } from '@angular/core'; import { caretAltLeftIcon, caretAltRightIcon } from '@progress/kendo-svg-icons'; import { Subscription } from 'rxjs'; import { TimelineCardComponent } from './timeline-card.component'; import { Keys, ResizeSensorComponent, guid, isChanged, isDocumentAvailable, isPresent } from '@progress/kendo-angular-common'; import { animate, state, style, transition, trigger } from '@angular/animations'; import { TimelineService } from './timeline.service'; import { LocalizationService } from '@progress/kendo-angular-l10n'; import { TimelineCardBodyTemplateDirective } from './templates/timeline-card-body.directive'; import { TimelineCardHeaderTemplateDirective } from './templates/timeline-card-header.directive'; import { TimelineCardActionsTemplateDirective } from './templates/timeline-card-actions.directive'; import { DatePipe } from '@progress/kendo-angular-intl'; import { NgFor, NgIf, NgStyle } from '@angular/common'; import { ButtonComponent } from '@progress/kendo-angular-buttons'; import * as i0 from "@angular/core"; import * as i1 from "./timeline.service"; import * as i2 from "@progress/kendo-angular-l10n"; const DEFAULT_TAB_WIDTH = 200; const SPACE_BETWEEN_TABS = 25; const TRANSITION_EVENTS_COUNT = 3; /** * @hidden */ export class TimelineHorizontalComponent { cdr; _zone; renderer; timelineService; localization; events = []; alterMode; collapsibleEvents; navigable; showDateLabels; animationDuration; eventHeight; dateFormat; headerTemplate; bodyTemplate; actionsTemplate; cardElementRefs; circleElementRefs; flagElementRefs; trackElementRef; scrollableTrackElementRef; cardComponents; get selectedEvent() { return this._selectedEvent; } set selectedEvent(value) { if (this._selectedEvent === value) { return; } const newSelectedIndex = this.events.findIndex(event => event === value); if (newSelectedIndex === -1 && value !== null) { return; } this._selectedEvent = value; this.selectedEventIndex = newSelectedIndex; this.calloutStyle = this.calloutOffset; } trackWrapWidth; scrollableTrackWidth; cardWidth; svgLeftIcon = caretAltLeftIcon; svgRightIcon = caretAltRightIcon; calloutStyle; animationState = 'center'; translateValue = 0; eventsInInterval = [0, 1, 2]; selectedCardIndex = 0; selectedEventIndex; tabFlex; tabWidth = DEFAULT_TAB_WIDTH; visibleTabsCount; firstCircleInView = 0; visibleEvents = []; trackItems = []; previousTitle = 'previous'; nextTitle = 'next'; _selectedEvent; subscriptions = new Subscription(); constructor(cdr, _zone, renderer, timelineService, localization) { this.cdr = cdr; this._zone = _zone; this.renderer = renderer; this.timelineService = timelineService; this.localization = localization; } ngOnInit() { this.l10nChange(); this.subscriptions.add(this.localization.changes.subscribe(this.l10nChange.bind(this))); if (this.events.length > 0) { this.selectedEvent = this.events[0]; } this.events.forEach(event => { if (event.flag) { this.trackItems.push({ isFlag: event.flag }); } this.trackItems.push(event); }); } ngAfterViewInit() { if (!isDocumentAvailable()) { return; } this.subscriptions.add(this.renderer.listen(this.trackElementRef.nativeElement, 'keydown', this.onKeyDown.bind(this))); this.trackWrapWidth = this.trackElementRef.nativeElement.getBoundingClientRect().width; this.scrollableTrackWidth = this.scrollableTrackElementRef.nativeElement.getBoundingClientRect().width; this._zone.runOutsideAngular(() => { this.onCirclesChange(); this.subscriptions.add(this.circleElementRefs.changes.subscribe(this.onCirclesChange.bind(this))); this.subscriptions.add(this.cardElementRefs.changes.subscribe(this.onCardsChange.bind(this))); }); if (this.events.length === 0) { return; } this.onCardsChange(); if (this.cardComponents.get(this.selectedCardIndex)) { this.cardComponents.get(this.selectedCardIndex).calloutStyle = this.calloutOffset; this.focusTrackItem(0); } } ngOnChanges(changes) { if (isChanged('events', changes)) { if (!this.events || this.events.length === 0) { this.selectedEvent = null; this.trackItems = []; this.visibleEvents = []; } else { this.trackItems = []; this.events.forEach(event => { if (event.flag) { this.trackItems.push({ isFlag: event.flag }); } this.trackItems.push(event); }); this.visibleEvents = this.trackItems .slice(this.firstCircleInView, this.firstCircleInView + this.visibleTabsCount) .filter(event => !event.isFlag); this.selectedEvent = this.events[0]; this.cdr.detectChanges(); this.calloutStyle = this.calloutOffset; this.focusTrackItem(0); } } } ngOnDestroy() { this.subscriptions.unsubscribe(); } onResize() { if (!isDocumentAvailable()) { return; } if (this.trackWrapWidth === this.trackElementRef.nativeElement.getBoundingClientRect().width) { return; } this.cardWidth = this.cardComponents.get(this.selectedCardIndex).element.nativeElement.offsetWidth; this.transformCards(); this.trackWrapWidth = this.trackElementRef.nativeElement.getBoundingClientRect().width; this.scrollableTrackWidth = this.scrollableTrackElementRef.nativeElement.getBoundingClientRect().width; this.changeTabsCount(); this._zone.run(() => { this.cardComponents.get(this.selectedCardIndex).calloutStyle = this.calloutOffset; }); } onTransitionEnd() { this.cardElementRefs?.forEach(card => this.renderer.removeStyle(card.nativeElement, 'transition-duration')); this.cardComponents.get(this.selectedCardIndex).event = this.selectedEvent; this.calloutStyle = this.calloutOffset; } onTrackTransitionEnd() { this.calloutStyle = this.calloutOffset; } onSlideDone() { this.calloutStyle = this.calloutOffset; } previous() { if (this.firstCircleInView === 0) { return; } this.updateInterval(false); } previousClick() { this.previous(); this.timelineService.onNavigate('previous'); } next() { if (!this.visibleTabsCount || this.firstCircleInView + this.visibleTabsCount > this.trackItems.length) { return; } this.updateInterval(true); } nextClick() { this.next(); this.timelineService.onNavigate('next'); } open(index) { if (index < 0 || index >= this.events.length) { return; } if (this.visibleEvents.findIndex(event => event === this.events[index]) === -1) { // determine the start and end of the interval that the event belongs to, regardless of its position in the interval const trackItemIndex = this.trackItems.findIndex(event => event === this.events[index]); const start = Math.floor(trackItemIndex / this.visibleTabsCount) * this.visibleTabsCount; this.navigateToInterval(start, index); } this.selectedEvent = this.events[index]; this.selectedCardIndex = this.getOtherSelectedCardIndex(index > this.selectedEventIndex); this.calloutStyle = this.calloutOffset; this.focusTrackItem(this.selectedEventIndex); this.animateCards(); } navigateToEvent(index) { const eventIndex = this.events.findIndex(event => event === this.trackItems[index]); if (this.selectedEventIndex === eventIndex) { return; } this.selectedEvent = this.events[eventIndex]; this.selectedCardIndex = this.getOtherSelectedCardIndex(index > eventIndex); this.calloutStyle = this.calloutOffset; this.animateCards(); } getOtherSelectedCardIndex(forward) { // change the selected card which changes all cards' transform styles if (forward) { return this.selectedCardIndex === 0 ? TRANSITION_EVENTS_COUNT - 1 : this.selectedCardIndex - 1; } return this.selectedCardIndex === TRANSITION_EVENTS_COUNT - 1 ? 0 : this.selectedCardIndex + 1; } tabStyle() { if (!this.tabFlex) { return {}; } return { 'flex': `1 0 ${this.tabFlex}%` }; } getTransformation(width, position) { if (position === this.selectedCardIndex - 1 || position === this.selectedCardIndex + 2) { return `translate3d(${-width}px, 0, 0)`; } if (position === this.selectedCardIndex + 1 || position === this.selectedCardIndex - 2) { return `translate3d(${width}px, 0, 0)`; } return `translate3d(0, 0, 0)`; } getState(position) { if (position === this.selectedCardIndex) { return 'center'; } if (position === this.selectedCardIndex - 1 || position === this.selectedCardIndex + 2) { return 'left'; } return 'right'; } get calloutOffset() { if (!isDocumentAvailable() || (!this.circleElementRefs?.first || !this.trackElementRef || !isPresent(this.selectedEventIndex))) { return {}; } const circleCenter = this.circleElementRefs.get(this.selectedEventIndex).nativeElement.getBoundingClientRect().left + this.circleElementRefs.get(this.selectedEventIndex).nativeElement.offsetWidth / 2; const trackOffset = this.trackElementRef.nativeElement.getBoundingClientRect().left; return { left: `${circleCenter - trackOffset}px` }; } get isFirstRange() { return this.firstCircleInView === 0; } get isLastRange() { if (!this.circleElementRefs?.first && !this.flagElementRefs?.first) { return false; } return this.trackItems.length === 0 || this.firstCircleInView + this.visibleTabsCount >= this.trackItems.length; } onCardsChange() { if (this.cardElementRefs?.get(this.selectedCardIndex)) { this.cardWidth = this.cardElementRefs.get(this.selectedCardIndex).nativeElement.offsetWidth; this.transformCards(); } } onCirclesChange() { if (!this.circleElementRefs?.first) { return; } this.circleElementRefs .map(element => element.nativeElement) .forEach((element, index) => { this.subscriptions.add(this.renderer.listen(element, 'click', () => { this.focusTrackItem(index); })); }); const width = this.circleElementRefs.first.nativeElement.getBoundingClientRect().width; if (width > DEFAULT_TAB_WIDTH) { this.tabWidth = this.circleElementRefs.first.nativeElement.getBoundingClientRect().width + SPACE_BETWEEN_TABS; } this.changeTabsCount(); this.visibleEvents = this.trackItems .slice(this.firstCircleInView, this.firstCircleInView + this.visibleTabsCount) .filter(event => !event.isFlag); } onKeyDown(event) { if (!this.navigable) { return; } event.preventDefault(); if (event.keyCode === Keys.Home) { this.onHomeKey(); } else if (event.keyCode === Keys.End) { this.onEndKey(); } else if (event.keyCode === Keys.ArrowRight) { this.onArrowRightKey(); } else if (event.keyCode === Keys.ArrowLeft) { this.onArrowLeftKey(); } } focusTrackItem(index) { if (!isDocumentAvailable()) { return; } if (!this.circleElementRefs || index < 0 || index >= this.circleElementRefs.length) { return; } const selectedTrackItem = this.circleElementRefs .find(element => element.nativeElement.hasAttribute('aria-selected')); if (selectedTrackItem) { this.removeTrackItemAttributes(selectedTrackItem); this.removeCardsAttributes(); } const newTrackItem = this.circleElementRefs.get(index).nativeElement; this.setTrackItemAttributes(newTrackItem, index); } setTrackItemAttributes(element, index) { if (!isDocumentAvailable()) { return; } const innerCard = this.cardComponents.get(this.selectedCardIndex).element.nativeElement.querySelector('.k-card'); const selectedCircle = this.circleElementRefs.get(index).nativeElement; this.renderer.addClass(element, 'k-focus'); this.renderer.setAttribute(element, 'aria-selected', 'true'); this.assignAriaLabel(innerCard, selectedCircle); this.assignAriaDescribedBy(innerCard, selectedCircle); } removeTrackItemAttributes(element) { this.renderer.removeClass(element.nativeElement, 'k-focus'); this.renderer.removeAttribute(element.nativeElement, 'aria-selected'); this.renderer.removeAttribute(element.nativeElement, 'id'); this.renderer.removeAttribute(element.nativeElement, 'aria-describedby'); } removeCardsAttributes() { this.cardElementRefs.forEach(card => { this.renderer.removeAttribute(card.nativeElement.querySelector('.k-card'), 'id'); this.renderer.removeAttribute(card.nativeElement.querySelector('.k-card'), 'aria-label'); }); } assignAriaLabel(cardElement, dateElement) { const dateLabelId = `k-${guid()}`; this.renderer.setAttribute(dateElement, 'id', dateLabelId); this.renderer.setAttribute(cardElement, 'aria-label', dateLabelId); } assignAriaDescribedBy(cardElement, dateElement) { const cardId = `k-${guid()}`; this.renderer.setAttribute(cardElement, 'id', cardId); this.renderer.setAttribute(dateElement, 'aria-describedby', cardId); } updateInterval(forward) { let start = forward ? this.firstCircleInView + this.visibleTabsCount : this.firstCircleInView - this.visibleTabsCount; if (start < 0 || start >= this.trackItems.length) { start = 0; } this.navigateToInterval(start, 0, forward, !forward); } onHomeKey() { if (this.selectedEvent === this.events[0]) { return; } this.navigateToFirstInterval(); } onEndKey() { if (this.selectedEvent === this.events[this.events.length - 1]) { return; } this.navigateToLastInterval(); } onArrowRightKey() { this.navigateToOtherEvent(true); } onArrowLeftKey() { this.navigateToOtherEvent(false); } navigateToFirstInterval() { this.navigateToInterval(0); } navigateToLastInterval() { const start = Math.floor((this.trackItems.length - 1) / this.visibleTabsCount) * this.visibleTabsCount; this.navigateToInterval(start, this.events.length - 1); } navigateToOtherEvent(direction) { const offset = direction ? 1 : -1; const newIndex = this.selectedEventIndex + offset; if (newIndex < 0 || newIndex >= this.events.length) { return; } if (this.visibleEvents.findIndex(event => event === this.events[newIndex]) === -1) { this.updateInterval(direction); } else { this.selectedEvent = this.events[newIndex]; this.selectedCardIndex = this.getOtherSelectedCardIndex(direction); this.focusTrackItem(this.selectedEventIndex); this.animateCards(); this.cdr.markForCheck(); } } navigateToInterval(start, selectedIndex = 0, selectFirst = false, selectLast = false) { const end = start + this.visibleTabsCount < this.trackItems.length ? start + this.visibleTabsCount : undefined; const forward = this.firstCircleInView < start; this.firstCircleInView = start; const interval = Math.floor(start / this.visibleTabsCount); this.translateValue = interval * -100; this.animationState = forward ? 'right' : 'left'; this.visibleEvents = this.trackItems.slice(this.firstCircleInView, end).filter(event => !event.isFlag); if (selectFirst) { this.selectedEvent = this.visibleEvents[0]; } else if (selectLast) { this.selectedEvent = this.visibleEvents[this.visibleEvents.length - 1]; } else { this.selectedEvent = this.events[selectedIndex]; } this.selectedCardIndex = this.getOtherSelectedCardIndex(forward); this.cdr.detectChanges(); this.focusTrackItem(this.selectedEventIndex); this.animateCards(); this.calloutStyle = this.calloutOffset; this.cdr.markForCheck(); } animateCards() { if (this.animationDuration) { this.cardComponents.get(this.selectedCardIndex).event = null; } this.cardElementRefs.forEach((card, index) => { this.renderer.setStyle(card.nativeElement, 'transform', this.getTransformation(this.cardWidth, index)); this.renderer.setStyle(card.nativeElement, 'transition-duration', `${this.animationDuration || 0}ms`); }); } transformCards() { this.cardElementRefs.forEach((card, index) => this.renderer.setStyle(card.nativeElement, 'transform', this.getTransformation(this.cardWidth, index))); } changeTabsCount() { this.visibleTabsCount = Math.round(this.scrollableTrackWidth / this.tabWidth); if (this.tabFlex !== 100 / this.visibleTabsCount) { this.tabFlex = 100 / this.visibleTabsCount; this.circleElementRefs.forEach(item => this.renderer.setStyle(item.nativeElement, 'flex', `1 0 ${this.tabFlex}%`)); this.flagElementRefs.forEach(item => this.renderer.setStyle(item.nativeElement, 'flex', `1 0 ${this.tabFlex}%`)); this.cdr.detectChanges(); this.visibleEvents = this.trackItems .slice(this.firstCircleInView, this.firstCircleInView + this.visibleTabsCount) .filter(event => !event.isFlag); if (!this.visibleEvents.find(event => event === this.selectedEvent)) { const trackItemIndex = this.trackItems.findIndex(event => event === this.selectedEvent); this.navigateToInterval(trackItemIndex, this.selectedEventIndex); } } } l10nChange() { if (this.localization.get('previous')) { this.previousTitle = this.localization.get('previous'); } if (this.localization.get('next')) { this.nextTitle = this.localization.get('next'); } this.cdr.markForCheck(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TimelineHorizontalComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i1.TimelineService }, { token: i2.LocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TimelineHorizontalComponent, isStandalone: true, selector: "kendo-timeline-horizontal", inputs: { events: "events", alterMode: "alterMode", collapsibleEvents: "collapsibleEvents", navigable: "navigable", showDateLabels: "showDateLabels", animationDuration: "animationDuration", eventHeight: "eventHeight", dateFormat: "dateFormat", headerTemplate: "headerTemplate", bodyTemplate: "bodyTemplate", actionsTemplate: "actionsTemplate" }, providers: [], viewQueries: [{ propertyName: "trackElementRef", first: true, predicate: ["track"], descendants: true }, { propertyName: "scrollableTrackElementRef", first: true, predicate: ["scrollableTrack"], descendants: true }, { propertyName: "cardElementRefs", predicate: ["card"], descendants: true, read: ElementRef }, { propertyName: "circleElementRefs", predicate: ["trackCircle"], descendants: true }, { propertyName: "flagElementRefs", predicate: ["trackFlag"], descendants: true }, { propertyName: "cardComponents", predicate: TimelineCardComponent, descendants: true }], exportAs: ["kendoTimelineHorizontal"], usesOnChanges: true, ngImport: i0, template: ` <div class="k-timeline-track-wrap" #track> <button kendoButton [svgIcon]="svgLeftIcon" icon="caret-alt-left" class="k-timeline-arrow k-timeline-arrow-left" rounded="full" [title]="previousTitle" (click)="previousClick()" [disabled]="isFirstRange" tabindex="-1" type="button" ></button> <button kendoButton [svgIcon]="svgRightIcon" icon="caret-alt-right" class="k-timeline-arrow k-timeline-arrow-right" rounded="full" [title]="nextTitle" (click)="nextClick()" [disabled]="isLastRange" tabindex="-1" type="button" ></button> <div class="k-timeline-track"> <ul class="k-timeline-scrollable-wrap" #scrollableTrack [attr.role]="'tablist'" [attr.tabindex]="'0'" [@trackSlide]="{value: animationState, params: {transformValue: this.translateValue}}" (@trackSlide.done)="onSlideDone()" (transitionend)="onTrackTransitionEnd()" > <ng-container *ngFor="let event of trackItems; let index = index"> <li #trackFlag *ngIf="event.isFlag" class="k-timeline-flag-wrap k-timeline-track-item" [attr.role]="'none'" [attr.aria-hidden]="true" [ngStyle]="tabStyle()" > <span class="k-timeline-flag">{{ event.isFlag }}</span> </li> <li *ngIf="!event.isFlag" #trackCircle class="k-timeline-track-item" [attr.role]="'tab'" (click)="navigateToEvent(index)" [ngStyle]="tabStyle()" > <div class="k-timeline-date-wrap"> <span *ngIf="showDateLabels" class="k-timeline-date"> {{ event.date | kendoDate: dateFormat }} </span> </div> <span class="k-timeline-circle"></span> </li> </ng-container> </ul> </div> </div> <div class="k-timeline-events-list"> <ul *ngIf="selectedEvent" class="k-timeline-scrollable-wrap" [@eventsSlide]="{value: animationState, params: {animationDuration: this.animationDuration || 0}}" (@eventsSlide.done)="onSlideDone()" [ngStyle]="{'transform-origin': 'left top'}" > <li *ngFor="let event of eventsInInterval; let index = index" #card class="k-timeline-event" (transitionend)="onTransitionEnd()" > <kendo-timeline-card [event]="selectedCardIndex === index ? selectedEvent : null" [expanded]="true" [collapsible]="collapsibleEvents" [calloutStyle]="selectedCardIndex === index ? calloutStyle : {}" [ngStyle]="{visibility: selectedCardIndex === index ? 'visible' : 'hidden' }" [tabIndex]="selectedCardIndex === index ? '0' : '-1'" [navigable]="navigable" [index]="selectedEventIndex" [headerTemplate]="headerTemplate" [bodyTemplate]="bodyTemplate" [actionsTemplate]="actionsTemplate" [eventHeight]="eventHeight" orientation="horizontal" > </kendo-timeline-card> </li> </ul> <kendo-resize-sensor (resize)="onResize()" [rateLimit]="10"></kendo-resize-sensor> </div> `, isInline: true, dependencies: [{ 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: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: TimelineCardComponent, selector: "kendo-timeline-card", inputs: ["event", "expanded", "collapsible", "reversed", "orientation", "navigable", "tabIndex", "animationDuration", "index", "eventWidth", "eventHeight", "headerTemplate", "bodyTemplate", "actionsTemplate", "calloutStyle"], exportAs: ["kendoTimelineCard"] }, { kind: "pipe", type: DatePipe, name: "kendoDate" }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }], animations: [ trigger('trackSlide', [ state('left', style({ transform: `translateX({{transformValue}}%)`, }), { params: { transformValue: '0' } }), state('right', style({ transform: `translateX({{transformValue}}%)`, }), { params: { transformValue: '0' } }), state('center', style({ transform: `translateX(0)`, })) ]), trigger('eventsSlide', [ transition('* => right', [ animate('{{animationDuration}}ms', style({ transform: `translateX(-100%)` })) ], { params: { animationDuration: '400' } }), transition('* => left', [ animate('{{animationDuration}}ms', style({ transform: `translateX(100%)` })) ], { params: { animationDuration: '400' } }) ]) ] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TimelineHorizontalComponent, decorators: [{ type: Component, args: [{ animations: [ trigger('trackSlide', [ state('left', style({ transform: `translateX({{transformValue}}%)`, }), { params: { transformValue: '0' } }), state('right', style({ transform: `translateX({{transformValue}}%)`, }), { params: { transformValue: '0' } }), state('center', style({ transform: `translateX(0)`, })) ]), trigger('eventsSlide', [ transition('* => right', [ animate('{{animationDuration}}ms', style({ transform: `translateX(-100%)` })) ], { params: { animationDuration: '400' } }), transition('* => left', [ animate('{{animationDuration}}ms', style({ transform: `translateX(100%)` })) ], { params: { animationDuration: '400' } }) ]) ], providers: [], exportAs: 'kendoTimelineHorizontal', selector: 'kendo-timeline-horizontal', template: ` <div class="k-timeline-track-wrap" #track> <button kendoButton [svgIcon]="svgLeftIcon" icon="caret-alt-left" class="k-timeline-arrow k-timeline-arrow-left" rounded="full" [title]="previousTitle" (click)="previousClick()" [disabled]="isFirstRange" tabindex="-1" type="button" ></button> <button kendoButton [svgIcon]="svgRightIcon" icon="caret-alt-right" class="k-timeline-arrow k-timeline-arrow-right" rounded="full" [title]="nextTitle" (click)="nextClick()" [disabled]="isLastRange" tabindex="-1" type="button" ></button> <div class="k-timeline-track"> <ul class="k-timeline-scrollable-wrap" #scrollableTrack [attr.role]="'tablist'" [attr.tabindex]="'0'" [@trackSlide]="{value: animationState, params: {transformValue: this.translateValue}}" (@trackSlide.done)="onSlideDone()" (transitionend)="onTrackTransitionEnd()" > <ng-container *ngFor="let event of trackItems; let index = index"> <li #trackFlag *ngIf="event.isFlag" class="k-timeline-flag-wrap k-timeline-track-item" [attr.role]="'none'" [attr.aria-hidden]="true" [ngStyle]="tabStyle()" > <span class="k-timeline-flag">{{ event.isFlag }}</span> </li> <li *ngIf="!event.isFlag" #trackCircle class="k-timeline-track-item" [attr.role]="'tab'" (click)="navigateToEvent(index)" [ngStyle]="tabStyle()" > <div class="k-timeline-date-wrap"> <span *ngIf="showDateLabels" class="k-timeline-date"> {{ event.date | kendoDate: dateFormat }} </span> </div> <span class="k-timeline-circle"></span> </li> </ng-container> </ul> </div> </div> <div class="k-timeline-events-list"> <ul *ngIf="selectedEvent" class="k-timeline-scrollable-wrap" [@eventsSlide]="{value: animationState, params: {animationDuration: this.animationDuration || 0}}" (@eventsSlide.done)="onSlideDone()" [ngStyle]="{'transform-origin': 'left top'}" > <li *ngFor="let event of eventsInInterval; let index = index" #card class="k-timeline-event" (transitionend)="onTransitionEnd()" > <kendo-timeline-card [event]="selectedCardIndex === index ? selectedEvent : null" [expanded]="true" [collapsible]="collapsibleEvents" [calloutStyle]="selectedCardIndex === index ? calloutStyle : {}" [ngStyle]="{visibility: selectedCardIndex === index ? 'visible' : 'hidden' }" [tabIndex]="selectedCardIndex === index ? '0' : '-1'" [navigable]="navigable" [index]="selectedEventIndex" [headerTemplate]="headerTemplate" [bodyTemplate]="bodyTemplate" [actionsTemplate]="actionsTemplate" [eventHeight]="eventHeight" orientation="horizontal" > </kendo-timeline-card> </li> </ul> <kendo-resize-sensor (resize)="onResize()" [rateLimit]="10"></kendo-resize-sensor> </div> `, standalone: true, imports: [ButtonComponent, NgFor, NgIf, NgStyle, TimelineCardComponent, DatePipe, ResizeSensorComponent] }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i1.TimelineService }, { type: i2.LocalizationService }]; }, propDecorators: { events: [{ type: Input }], alterMode: [{ type: Input }], collapsibleEvents: [{ type: Input }], navigable: [{ type: Input }], showDateLabels: [{ type: Input }], animationDuration: [{ type: Input }], eventHeight: [{ type: Input }], dateFormat: [{ type: Input }], headerTemplate: [{ type: Input }], bodyTemplate: [{ type: Input }], actionsTemplate: [{ type: Input }], cardElementRefs: [{ type: ViewChildren, args: ['card', { read: ElementRef }] }], circleElementRefs: [{ type: ViewChildren, args: ['trackCircle'] }], flagElementRefs: [{ type: ViewChildren, args: ['trackFlag'] }], trackElementRef: [{ type: ViewChild, args: ['track'] }], scrollableTrackElementRef: [{ type: ViewChild, args: ['scrollableTrack'] }], cardComponents: [{ type: ViewChildren, args: [TimelineCardComponent] }] } });