@progress/kendo-angular-layout
Version: 
Kendo UI for Angular Layout Package - a collection of components to create professional application layoyts
774 lines (773 loc) • 36 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* 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, normalizeNumpadKeys } 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;
        }
        const code = normalizeNumpadKeys(event);
        event.preventDefault();
        if (code === Keys.Home) {
            this.onHomeKey();
        }
        else if (code === Keys.End) {
            this.onEndKey();
        }
        else if (code === Keys.ArrowRight) {
            this.onArrowRightKey();
        }
        else if (code === 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'"
                    []="{value: animationState, params: {transformValue: this.translateValue}}"
                    (.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"
                []="{value: animationState, params: {animationDuration: this.animationDuration || 0}}"
                (.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'"
                    []="{value: animationState, params: {transformValue: this.translateValue}}"
                    (.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"
                []="{value: animationState, params: {animationDuration: this.animationDuration || 0}}"
                (.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]
            }] } });