@masterteam/timeline 0.0.8 → 0.0.9

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.
@@ -1,11 +1,15 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule, NgTemplateOutlet } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, TemplateRef, Directive, Input, input, output, Component, signal, computed, ViewChild, model, contentChild, contentChildren } from '@angular/core';
4
+ import { inject, TemplateRef, Directive, Input, input, output, Component, ChangeDetectionStrategy, signal, computed, ViewChild, DestroyRef, model, contentChild, contentChildren } from '@angular/core';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
5
7
  import { Popover } from 'primeng/popover';
8
+ import { Tooltip } from 'primeng/tooltip';
6
9
  import { Icon } from '@masterteam/icons';
7
10
  import * as i1$1 from '@angular/forms';
8
11
  import { FormsModule } from '@angular/forms';
12
+ import { Button } from '@masterteam/components/button';
9
13
  import { SelectField } from '@masterteam/components/select-field';
10
14
 
11
15
  class TimelineGanttTemplateDirective {
@@ -77,11 +81,11 @@ class TimelineDefaultPopover {
77
81
  // Requests parent popover host to close.
78
82
  requestClose = output();
79
83
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineDefaultPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: TimelineDefaultPopover, isStandalone: true, selector: "mt-timeline-default-popover", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { requestClose: "requestClose" }, ngImport: i0, template: "<!-- Default details view shown inside PrimeNG popover. -->\r\n<div class=\"w-[22.5rem]\">\r\n <div class=\"mb-3 flex items-center justify-between\">\r\n <h4 class=\"text-sm font-semibold\">Level Details</h4>\r\n <button\r\n type=\"button\"\r\n class=\"rounded border border-surface px-2 py-1 text-xs\"\r\n (click)=\"requestClose.emit()\"\r\n >\r\n Close\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid gap-2 text-sm sm:grid-cols-2\">\r\n <div><span class=\"font-semibold\">Name:</span> {{ item().title }}</div>\r\n <div>\r\n <span class=\"font-semibold\">Level:</span>\r\n {{ item().levelDescription }}\r\n </div>\r\n <div><span class=\"font-semibold\">Owner:</span> {{ item().owner }}</div>\r\n <div>\r\n <span class=\"font-semibold\">Status:</span>\r\n <span [style.color]=\"item().statusColor\">{{ item().statusName }}</span>\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">Progress:</span>\r\n {{ item().progressLabel }}\r\n </div>\r\n <div><span class=\"font-semibold\">Range:</span> {{ item().phase }}</div>\r\n </div>\r\n</div>\r\n" });
84
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: TimelineDefaultPopover, isStandalone: true, selector: "mt-timeline-default-popover", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { requestClose: "requestClose" }, ngImport: i0, template: "<!-- Default details view shown inside PrimeNG popover. -->\r\n<div class=\"w-[22.5rem]\" *transloco=\"let t; prefix: 'timeline'\">\r\n <div class=\"mb-3 flex items-center justify-between\">\r\n <h4 class=\"text-sm font-semibold\">{{ t(\"level-details\") }}</h4>\r\n <button\r\n type=\"button\"\r\n class=\"rounded border border-surface px-2 py-1 text-xs\"\r\n (click)=\"requestClose.emit()\"\r\n >\r\n {{ t(\"close\") }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid gap-2 text-sm sm:grid-cols-2\">\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"name\") }}:</span> {{ item().title }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"level\") }}:</span>\r\n {{ item().levelDescription }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"owner\") }}:</span> {{ item().owner }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"status\") }}:</span>\r\n <span [style.color]=\"item().statusColor\">{{ item().statusName }}</span>\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"progress\") }}:</span>\r\n {{ item().progressLabel }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"range\") }}:</span> {{ item().phase }}\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
81
85
  }
82
86
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineDefaultPopover, decorators: [{
83
87
  type: Component,
84
- args: [{ selector: 'mt-timeline-default-popover', standalone: true, template: "<!-- Default details view shown inside PrimeNG popover. -->\r\n<div class=\"w-[22.5rem]\">\r\n <div class=\"mb-3 flex items-center justify-between\">\r\n <h4 class=\"text-sm font-semibold\">Level Details</h4>\r\n <button\r\n type=\"button\"\r\n class=\"rounded border border-surface px-2 py-1 text-xs\"\r\n (click)=\"requestClose.emit()\"\r\n >\r\n Close\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid gap-2 text-sm sm:grid-cols-2\">\r\n <div><span class=\"font-semibold\">Name:</span> {{ item().title }}</div>\r\n <div>\r\n <span class=\"font-semibold\">Level:</span>\r\n {{ item().levelDescription }}\r\n </div>\r\n <div><span class=\"font-semibold\">Owner:</span> {{ item().owner }}</div>\r\n <div>\r\n <span class=\"font-semibold\">Status:</span>\r\n <span [style.color]=\"item().statusColor\">{{ item().statusName }}</span>\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">Progress:</span>\r\n {{ item().progressLabel }}\r\n </div>\r\n <div><span class=\"font-semibold\">Range:</span> {{ item().phase }}</div>\r\n </div>\r\n</div>\r\n" }]
88
+ args: [{ selector: 'mt-timeline-default-popover', standalone: true, imports: [TranslocoDirective], template: "<!-- Default details view shown inside PrimeNG popover. -->\r\n<div class=\"w-[22.5rem]\" *transloco=\"let t; prefix: 'timeline'\">\r\n <div class=\"mb-3 flex items-center justify-between\">\r\n <h4 class=\"text-sm font-semibold\">{{ t(\"level-details\") }}</h4>\r\n <button\r\n type=\"button\"\r\n class=\"rounded border border-surface px-2 py-1 text-xs\"\r\n (click)=\"requestClose.emit()\"\r\n >\r\n {{ t(\"close\") }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid gap-2 text-sm sm:grid-cols-2\">\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"name\") }}:</span> {{ item().title }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"level\") }}:</span>\r\n {{ item().levelDescription }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"owner\") }}:</span> {{ item().owner }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"status\") }}:</span>\r\n <span [style.color]=\"item().statusColor\">{{ item().statusName }}</span>\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"progress\") }}:</span>\r\n {{ item().progressLabel }}\r\n </div>\r\n <div>\r\n <span class=\"font-semibold\">{{ t(\"range\") }}:</span> {{ item().phase }}\r\n </div>\r\n </div>\r\n</div>\r\n" }]
85
89
  }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], requestClose: [{ type: i0.Output, args: ["requestClose"] }] } });
86
90
 
87
91
  /**
@@ -111,6 +115,7 @@ class TimelineGanttHeader {
111
115
  orderedGanttSegments = input([], ...(ngDevMode ? [{ debugName: "orderedGanttSegments" }] : []));
112
116
  ganttCanvasWidth = input(0, ...(ngDevMode ? [{ debugName: "ganttCanvasWidth" }] : []));
113
117
  effectiveGanttSegmentWidthPx = input(96, ...(ngDevMode ? [{ debugName: "effectiveGanttSegmentWidthPx" }] : []));
118
+ zoomToFit = input(false, ...(ngDevMode ? [{ debugName: "zoomToFit" }] : []));
114
119
  renderColumns = input(true, ...(ngDevMode ? [{ debugName: "renderColumns" }] : []));
115
120
  renderTimeline = input(true, ...(ngDevMode ? [{ debugName: "renderTimeline" }] : []));
116
121
  // Converts monthly segments from "M N" to calendar abbreviations.
@@ -123,20 +128,25 @@ class TimelineGanttHeader {
123
128
  ? this.monthLabels[month - 1]
124
129
  : segment.title;
125
130
  }
126
- resolveHeaderAlignClass(column) {
127
- return {
128
- 'text-start': column.position === 'start',
129
- 'text-center': column.position === 'center',
130
- 'text-end': column.position === 'end',
131
- };
131
+ shouldRenderSegmentYear() {
132
+ return this.effectiveGanttSegmentWidthPx() >= 84;
133
+ }
134
+ resolveSegmentTitleAttr(segment) {
135
+ if (segment.year === undefined || segment.year === null) {
136
+ return this.resolveSegmentTitle(segment);
137
+ }
138
+ return `${this.resolveSegmentTitle(segment)} ${segment.year}`;
139
+ }
140
+ resolveSegmentTooltip(segment) {
141
+ return this.resolveSegmentTitleAttr(segment);
132
142
  }
133
143
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGanttHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
134
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGanttHeader, isStandalone: true, selector: "mt-timeline-gantt-header", inputs: { timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, resolvedColumns: { classPropertyName: "resolvedColumns", publicName: "resolvedColumns", isSignal: true, isRequired: false, transformFunction: null }, orderedGanttSegments: { classPropertyName: "orderedGanttSegments", publicName: "orderedGanttSegments", isSignal: true, isRequired: false, transformFunction: null }, ganttCanvasWidth: { classPropertyName: "ganttCanvasWidth", publicName: "ganttCanvasWidth", isSignal: true, isRequired: false, transformFunction: null }, effectiveGanttSegmentWidthPx: { classPropertyName: "effectiveGanttSegmentWidthPx", publicName: "effectiveGanttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, renderColumns: { classPropertyName: "renderColumns", publicName: "renderColumns", isSignal: true, isRequired: false, transformFunction: null }, renderTimeline: { classPropertyName: "renderTimeline", publicName: "renderTimeline", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block min-w-0" }, ngImport: i0, template: "<!-- Sticky metadata columns + timeline period header. -->\r\n<div class=\"flex border-b border-surface bg-surface-50\">\r\n <!-- Left sticky columns (title/status/custom columns). -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface bg-surface-50 p-3 text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"column.widthPx\"\r\n [ngClass]=\"resolveHeaderAlignClass(column)\"\r\n >\r\n {{ column.header }}\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Time scale columns (month/quarter/half/year). -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"flex shrink-0 items-center bg-surface-50\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n >\r\n @for (column of orderedGanttSegments(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface px-2 py-3 text-center text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"effectiveGanttSegmentWidthPx()\"\r\n >\r\n {{ resolveSegmentTitle(column) }}\r\n @if (column.year !== undefined && column.year !== null) {\r\n {{ column.year }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
144
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGanttHeader, isStandalone: true, selector: "mt-timeline-gantt-header", inputs: { timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, resolvedColumns: { classPropertyName: "resolvedColumns", publicName: "resolvedColumns", isSignal: true, isRequired: false, transformFunction: null }, orderedGanttSegments: { classPropertyName: "orderedGanttSegments", publicName: "orderedGanttSegments", isSignal: true, isRequired: false, transformFunction: null }, ganttCanvasWidth: { classPropertyName: "ganttCanvasWidth", publicName: "ganttCanvasWidth", isSignal: true, isRequired: false, transformFunction: null }, effectiveGanttSegmentWidthPx: { classPropertyName: "effectiveGanttSegmentWidthPx", publicName: "effectiveGanttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, zoomToFit: { classPropertyName: "zoomToFit", publicName: "zoomToFit", isSignal: true, isRequired: false, transformFunction: null }, renderColumns: { classPropertyName: "renderColumns", publicName: "renderColumns", isSignal: true, isRequired: false, transformFunction: null }, renderTimeline: { classPropertyName: "renderTimeline", publicName: "renderTimeline", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block min-w-0" }, ngImport: i0, template: "<!-- Sticky metadata columns + timeline period header. -->\r\n<div class=\"flex border-b border-surface bg-surface-50\">\r\n <!-- Left sticky columns (title/status/custom columns). -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface bg-surface-50 p-3 text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"column.widthPx\"\r\n [class.text-start]=\"column.position === 'start'\"\r\n [class.text-center]=\"column.position === 'center'\"\r\n [class.text-end]=\"column.position === 'end'\"\r\n >\r\n {{ column.header }}\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Time scale columns (month/quarter/half/year). -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"flex shrink-0 items-center bg-surface-50\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n >\r\n @for (column of orderedGanttSegments(); track $index) {\r\n <div\r\n class=\"shrink-0 overflow-hidden border-e border-surface px-2 py-3 text-center text-xs font-semibold uppercase text-surface-600 whitespace-nowrap\"\r\n [style.width.px]=\"effectiveGanttSegmentWidthPx()\"\r\n [pTooltip]=\"resolveSegmentTooltip(column)\"\r\n tooltipPosition=\"top\"\r\n [tooltipDisabled]=\"!zoomToFit()\"\r\n >\r\n {{ resolveSegmentTitle(column) }}\r\n @if (\r\n shouldRenderSegmentYear() &&\r\n column.year !== undefined &&\r\n column.year !== null\r\n ) {\r\n {{ column.year }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
135
145
  }
136
146
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGanttHeader, decorators: [{
137
147
  type: Component,
138
- args: [{ selector: 'mt-timeline-gantt-header', standalone: true, imports: [CommonModule], host: { class: 'block min-w-0' }, template: "<!-- Sticky metadata columns + timeline period header. -->\r\n<div class=\"flex border-b border-surface bg-surface-50\">\r\n <!-- Left sticky columns (title/status/custom columns). -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface bg-surface-50 p-3 text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"column.widthPx\"\r\n [ngClass]=\"resolveHeaderAlignClass(column)\"\r\n >\r\n {{ column.header }}\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Time scale columns (month/quarter/half/year). -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"flex shrink-0 items-center bg-surface-50\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n >\r\n @for (column of orderedGanttSegments(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface px-2 py-3 text-center text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"effectiveGanttSegmentWidthPx()\"\r\n >\r\n {{ resolveSegmentTitle(column) }}\r\n @if (column.year !== undefined && column.year !== null) {\r\n {{ column.year }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n" }]
139
- }], propDecorators: { timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], resolvedColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolvedColumns", required: false }] }], orderedGanttSegments: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderedGanttSegments", required: false }] }], ganttCanvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttCanvasWidth", required: false }] }], effectiveGanttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "effectiveGanttSegmentWidthPx", required: false }] }], renderColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderColumns", required: false }] }], renderTimeline: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderTimeline", required: false }] }] } });
148
+ args: [{ selector: 'mt-timeline-gantt-header', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, Tooltip], host: { class: 'block min-w-0' }, template: "<!-- Sticky metadata columns + timeline period header. -->\r\n<div class=\"flex border-b border-surface bg-surface-50\">\r\n <!-- Left sticky columns (title/status/custom columns). -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"shrink-0 border-e border-surface bg-surface-50 p-3 text-xs font-semibold uppercase text-surface-600\"\r\n [style.width.px]=\"column.widthPx\"\r\n [class.text-start]=\"column.position === 'start'\"\r\n [class.text-center]=\"column.position === 'center'\"\r\n [class.text-end]=\"column.position === 'end'\"\r\n >\r\n {{ column.header }}\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Time scale columns (month/quarter/half/year). -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"flex shrink-0 items-center bg-surface-50\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n >\r\n @for (column of orderedGanttSegments(); track $index) {\r\n <div\r\n class=\"shrink-0 overflow-hidden border-e border-surface px-2 py-3 text-center text-xs font-semibold uppercase text-surface-600 whitespace-nowrap\"\r\n [style.width.px]=\"effectiveGanttSegmentWidthPx()\"\r\n [pTooltip]=\"resolveSegmentTooltip(column)\"\r\n tooltipPosition=\"top\"\r\n [tooltipDisabled]=\"!zoomToFit()\"\r\n >\r\n {{ resolveSegmentTitle(column) }}\r\n @if (\r\n shouldRenderSegmentYear() &&\r\n column.year !== undefined &&\r\n column.year !== null\r\n ) {\r\n {{ column.year }}\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n" }]
149
+ }], propDecorators: { timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], resolvedColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolvedColumns", required: false }] }], orderedGanttSegments: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderedGanttSegments", required: false }] }], ganttCanvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttCanvasWidth", required: false }] }], effectiveGanttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "effectiveGanttSegmentWidthPx", required: false }] }], zoomToFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomToFit", required: false }] }], renderColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderColumns", required: false }] }], renderTimeline: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderTimeline", required: false }] }] } });
140
150
 
141
151
  /**
142
152
  * Single-row renderer for the Gantt body.
@@ -204,13 +214,6 @@ class TimelineGanttRow {
204
214
  }
205
215
  return this.path(item, column.key);
206
216
  }
207
- resolveColumnAlignClass(column) {
208
- return {
209
- 'justify-start': column.position === 'start',
210
- 'justify-center': column.position === 'center',
211
- 'justify-end': column.position === 'end',
212
- };
213
- }
214
217
  getColumnTemplateContext(column, item) {
215
218
  const source = item.source ?? item;
216
219
  return {
@@ -241,6 +244,12 @@ class TimelineGanttRow {
241
244
  onSelect: (event) => this.onProgressClick(item, event),
242
245
  };
243
246
  }
247
+ shouldRenderProgressLabel(item) {
248
+ return item.trackWidthPx >= 72;
249
+ }
250
+ resolveProgressFillMinWidthPx(item) {
251
+ return item.trackWidthPx > 0 ? Math.min(54, item.trackWidthPx) : 0;
252
+ }
244
253
  // Reads document direction to support sticky offsets and progress alignment.
245
254
  isRtl() {
246
255
  if (typeof document === 'undefined') {
@@ -270,11 +279,11 @@ class TimelineGanttRow {
270
279
  }, item);
271
280
  }
272
281
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGanttRow, deps: [], target: i0.ɵɵFactoryTarget.Component });
273
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGanttRow, isStandalone: true, selector: "mt-timeline-gantt-row", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, resolvedColumns: { classPropertyName: "resolvedColumns", publicName: "resolvedColumns", isSignal: true, isRequired: false, transformFunction: null }, ganttCanvasWidth: { classPropertyName: "ganttCanvasWidth", publicName: "ganttCanvasWidth", isSignal: true, isRequired: false, transformFunction: null }, laneInsetPx: { classPropertyName: "laneInsetPx", publicName: "laneInsetPx", isSignal: true, isRequired: false, transformFunction: null }, renderColumns: { classPropertyName: "renderColumns", publicName: "renderColumns", isSignal: true, isRequired: false, transformFunction: null }, renderTimeline: { classPropertyName: "renderTimeline", publicName: "renderTimeline", isSignal: true, isRequired: false, transformFunction: null }, columnTemplatesByKey: { classPropertyName: "columnTemplatesByKey", publicName: "columnTemplatesByKey", isSignal: true, isRequired: false, transformFunction: null }, progressTemplateDirective: { classPropertyName: "progressTemplateDirective", publicName: "progressTemplateDirective", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleCollapse: "toggleCollapse", progressClick: "progressClick" }, host: { classAttribute: "block min-w-0" }, ngImport: i0, template: "<!-- One gantt data row: sticky metadata cells + progress lane. -->\r\n<div class=\"relative flex\">\r\n <!-- Left sticky metadata cells. -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"flex h-16 shrink-0 items-center overflow-hidden border-e border-b border-surface bg-content p-3\"\r\n [style.width.px]=\"column.widthPx\"\r\n [ngClass]=\"resolveColumnAlignClass(column)\"\r\n >\r\n <!-- Per-column custom template, when provided by consumer. -->\r\n @if (resolveColumnTemplate(column); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"getColumnTemplateContext(column, item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in fallback renderers by column configuration. -->\r\n @if (column.isTreeColumn) {\r\n <div\r\n class=\"flex min-w-0 items-center gap-2\"\r\n [style.padding-inline-start.px]=\"item().levelDepth * 16\"\r\n >\r\n @if (item().hasChildren) {\r\n <mt-icon\r\n class=\"cursor-pointer\"\r\n (click)=\"onToggleCollapse(item())\"\r\n [icon]=\"collapseIcon(item())\"\r\n ></mt-icon>\r\n } @else {\r\n <span class=\"inline-block w-5\"></span>\r\n }\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n </div>\r\n } @else {\r\n <span class=\"truncate text-sm\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Right timeline canvas cell for progress track/fill. -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"relative z-0 h-16 shrink-0 overflow-hidden border-b border-surface py-4\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n [style.z-index]=\"1\"\r\n >\r\n <div class=\"h-8\"></div>\r\n <!-- Consumer custom progress template. -->\r\n @if (progressTemplateDirective(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getProgressTemplateContext(item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in progress renderer. -->\r\n <div\r\n class=\"absolute top-1/2 h-7 -translate-y-1/2 cursor-pointer rounded-full\"\r\n [style.left.px]=\"\r\n isRtl() ? null : item().startOffsetPx + laneInsetPx()\r\n \"\r\n [style.right.px]=\"\r\n isRtl() ? item().startOffsetPx + laneInsetPx() : null\r\n \"\r\n [style.width.px]=\"item().trackWidthPx\"\r\n [style.background-color]=\"item().progressTrackColor\"\r\n [style.z-index]=\"1\"\r\n [attr.title]=\"item().progressLabel\"\r\n (click)=\"onProgressClick(item(), $event)\"\r\n >\r\n @if (item().progressFillWidthPx > 0) {\r\n <div\r\n class=\"h-full rounded-full\"\r\n [style.width.px]=\"item().progressFillWidthPx\"\r\n [style.min-width.px]=\"54\"\r\n [style.background-color]=\"item().statusColor\"\r\n ></div>\r\n }\r\n\r\n <span\r\n class=\"pointer-events-none absolute top-1/2 z-[1] -translate-y-1/2 rounded-full bg-white px-2 py-0.5 text-[10px] font-semibold text-black shadow-sm\"\r\n [style.left.px]=\"isRtl() ? null : 8\"\r\n [style.right.px]=\"isRtl() ? 8 : null\"\r\n [attr.title]=\"item().progressLabel\"\r\n >\r\n {{ item().progressLabel }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }] });
282
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGanttRow, isStandalone: true, selector: "mt-timeline-gantt-row", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, resolvedColumns: { classPropertyName: "resolvedColumns", publicName: "resolvedColumns", isSignal: true, isRequired: false, transformFunction: null }, ganttCanvasWidth: { classPropertyName: "ganttCanvasWidth", publicName: "ganttCanvasWidth", isSignal: true, isRequired: false, transformFunction: null }, laneInsetPx: { classPropertyName: "laneInsetPx", publicName: "laneInsetPx", isSignal: true, isRequired: false, transformFunction: null }, renderColumns: { classPropertyName: "renderColumns", publicName: "renderColumns", isSignal: true, isRequired: false, transformFunction: null }, renderTimeline: { classPropertyName: "renderTimeline", publicName: "renderTimeline", isSignal: true, isRequired: false, transformFunction: null }, columnTemplatesByKey: { classPropertyName: "columnTemplatesByKey", publicName: "columnTemplatesByKey", isSignal: true, isRequired: false, transformFunction: null }, progressTemplateDirective: { classPropertyName: "progressTemplateDirective", publicName: "progressTemplateDirective", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleCollapse: "toggleCollapse", progressClick: "progressClick" }, host: { classAttribute: "block min-w-0" }, ngImport: i0, template: "<!-- One gantt data row: sticky metadata cells + progress lane. -->\r\n<div class=\"relative flex\">\r\n <!-- Left sticky metadata cells. -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"flex h-16 shrink-0 items-center overflow-hidden border-e border-b border-surface bg-content p-3\"\r\n [style.width.px]=\"column.widthPx\"\r\n [class.justify-start]=\"column.position === 'start'\"\r\n [class.justify-center]=\"column.position === 'center'\"\r\n [class.justify-end]=\"column.position === 'end'\"\r\n >\r\n <!-- Per-column custom template, when provided by consumer. -->\r\n @if (resolveColumnTemplate(column); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"getColumnTemplateContext(column, item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in fallback renderers by column configuration. -->\r\n @if (column.isTreeColumn) {\r\n <div\r\n class=\"flex min-w-0 items-center gap-2\"\r\n [style.padding-inline-start.px]=\"item().levelDepth * 16\"\r\n >\r\n @if (item().hasChildren) {\r\n <mt-icon\r\n class=\"cursor-pointer\"\r\n (click)=\"onToggleCollapse(item())\"\r\n [icon]=\"collapseIcon(item())\"\r\n ></mt-icon>\r\n } @else {\r\n <span class=\"inline-block w-5\"></span>\r\n }\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n </div>\r\n } @else {\r\n <span class=\"truncate text-sm\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Right timeline canvas cell for progress track/fill. -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"relative z-0 h-16 shrink-0 overflow-hidden border-b border-surface py-4\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n [style.z-index]=\"1\"\r\n >\r\n <div class=\"h-8\"></div>\r\n <!-- Consumer custom progress template. -->\r\n @if (progressTemplateDirective(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getProgressTemplateContext(item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in progress renderer. -->\r\n <div\r\n class=\"absolute top-1/2 h-7 -translate-y-1/2 cursor-pointer overflow-hidden rounded-full\"\r\n [style.left.px]=\"\r\n isRtl() ? null : item().startOffsetPx + laneInsetPx()\r\n \"\r\n [style.right.px]=\"\r\n isRtl() ? item().startOffsetPx + laneInsetPx() : null\r\n \"\r\n [style.width.px]=\"item().trackWidthPx\"\r\n [style.background-color]=\"item().progressTrackColor\"\r\n [style.z-index]=\"1\"\r\n [attr.title]=\"item().progressLabel\"\r\n (click)=\"onProgressClick(item(), $event)\"\r\n >\r\n @if (item().progressFillWidthPx > 0) {\r\n <div\r\n class=\"h-full rounded-full\"\r\n [style.width.px]=\"item().progressFillWidthPx\"\r\n [style.min-width.px]=\"resolveProgressFillMinWidthPx(item())\"\r\n [style.background-color]=\"item().statusColor\"\r\n ></div>\r\n }\r\n\r\n @if (shouldRenderProgressLabel(item())) {\r\n <span\r\n class=\"pointer-events-none absolute top-1/2 z-[1] -translate-y-1/2 rounded-full bg-white px-2 py-0.5 text-[10px] font-semibold text-black shadow-sm\"\r\n [style.left.px]=\"isRtl() ? null : 8\"\r\n [style.right.px]=\"isRtl() ? 8 : null\"\r\n [attr.title]=\"item().progressLabel\"\r\n >\r\n {{ item().progressLabel }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
274
283
  }
275
284
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGanttRow, decorators: [{
276
285
  type: Component,
277
- args: [{ selector: 'mt-timeline-gantt-row', standalone: true, imports: [CommonModule, Icon, NgTemplateOutlet], host: { class: 'block min-w-0' }, template: "<!-- One gantt data row: sticky metadata cells + progress lane. -->\r\n<div class=\"relative flex\">\r\n <!-- Left sticky metadata cells. -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"flex h-16 shrink-0 items-center overflow-hidden border-e border-b border-surface bg-content p-3\"\r\n [style.width.px]=\"column.widthPx\"\r\n [ngClass]=\"resolveColumnAlignClass(column)\"\r\n >\r\n <!-- Per-column custom template, when provided by consumer. -->\r\n @if (resolveColumnTemplate(column); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"getColumnTemplateContext(column, item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in fallback renderers by column configuration. -->\r\n @if (column.isTreeColumn) {\r\n <div\r\n class=\"flex min-w-0 items-center gap-2\"\r\n [style.padding-inline-start.px]=\"item().levelDepth * 16\"\r\n >\r\n @if (item().hasChildren) {\r\n <mt-icon\r\n class=\"cursor-pointer\"\r\n (click)=\"onToggleCollapse(item())\"\r\n [icon]=\"collapseIcon(item())\"\r\n ></mt-icon>\r\n } @else {\r\n <span class=\"inline-block w-5\"></span>\r\n }\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n </div>\r\n } @else {\r\n <span class=\"truncate text-sm\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Right timeline canvas cell for progress track/fill. -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"relative z-0 h-16 shrink-0 overflow-hidden border-b border-surface py-4\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n [style.z-index]=\"1\"\r\n >\r\n <div class=\"h-8\"></div>\r\n <!-- Consumer custom progress template. -->\r\n @if (progressTemplateDirective(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getProgressTemplateContext(item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in progress renderer. -->\r\n <div\r\n class=\"absolute top-1/2 h-7 -translate-y-1/2 cursor-pointer rounded-full\"\r\n [style.left.px]=\"\r\n isRtl() ? null : item().startOffsetPx + laneInsetPx()\r\n \"\r\n [style.right.px]=\"\r\n isRtl() ? item().startOffsetPx + laneInsetPx() : null\r\n \"\r\n [style.width.px]=\"item().trackWidthPx\"\r\n [style.background-color]=\"item().progressTrackColor\"\r\n [style.z-index]=\"1\"\r\n [attr.title]=\"item().progressLabel\"\r\n (click)=\"onProgressClick(item(), $event)\"\r\n >\r\n @if (item().progressFillWidthPx > 0) {\r\n <div\r\n class=\"h-full rounded-full\"\r\n [style.width.px]=\"item().progressFillWidthPx\"\r\n [style.min-width.px]=\"54\"\r\n [style.background-color]=\"item().statusColor\"\r\n ></div>\r\n }\r\n\r\n <span\r\n class=\"pointer-events-none absolute top-1/2 z-[1] -translate-y-1/2 rounded-full bg-white px-2 py-0.5 text-[10px] font-semibold text-black shadow-sm\"\r\n [style.left.px]=\"isRtl() ? null : 8\"\r\n [style.right.px]=\"isRtl() ? 8 : null\"\r\n [attr.title]=\"item().progressLabel\"\r\n >\r\n {{ item().progressLabel }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n" }]
286
+ args: [{ selector: 'mt-timeline-gantt-row', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, Icon, NgTemplateOutlet], host: { class: 'block min-w-0' }, template: "<!-- One gantt data row: sticky metadata cells + progress lane. -->\r\n<div class=\"relative flex\">\r\n <!-- Left sticky metadata cells. -->\r\n @if (renderColumns()) {\r\n @for (column of resolvedColumns(); track $index) {\r\n <div\r\n class=\"flex h-16 shrink-0 items-center overflow-hidden border-e border-b border-surface bg-content p-3\"\r\n [style.width.px]=\"column.widthPx\"\r\n [class.justify-start]=\"column.position === 'start'\"\r\n [class.justify-center]=\"column.position === 'center'\"\r\n [class.justify-end]=\"column.position === 'end'\"\r\n >\r\n <!-- Per-column custom template, when provided by consumer. -->\r\n @if (resolveColumnTemplate(column); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"getColumnTemplateContext(column, item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in fallback renderers by column configuration. -->\r\n @if (column.isTreeColumn) {\r\n <div\r\n class=\"flex min-w-0 items-center gap-2\"\r\n [style.padding-inline-start.px]=\"item().levelDepth * 16\"\r\n >\r\n @if (item().hasChildren) {\r\n <mt-icon\r\n class=\"cursor-pointer\"\r\n (click)=\"onToggleCollapse(item())\"\r\n [icon]=\"collapseIcon(item())\"\r\n ></mt-icon>\r\n } @else {\r\n <span class=\"inline-block w-5\"></span>\r\n }\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n </div>\r\n } @else {\r\n <span class=\"truncate text-sm\">\r\n {{ resolveColumnText(column, item()) }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Right timeline canvas cell for progress track/fill. -->\r\n @if (renderTimeline()) {\r\n <div\r\n class=\"relative z-0 h-16 shrink-0 overflow-hidden border-b border-surface py-4\"\r\n [style.width.px]=\"ganttCanvasWidth()\"\r\n [style.z-index]=\"1\"\r\n >\r\n <div class=\"h-8\"></div>\r\n <!-- Consumer custom progress template. -->\r\n @if (progressTemplateDirective(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getProgressTemplateContext(item())\"\r\n ></ng-container>\r\n } @else {\r\n <!-- Built-in progress renderer. -->\r\n <div\r\n class=\"absolute top-1/2 h-7 -translate-y-1/2 cursor-pointer overflow-hidden rounded-full\"\r\n [style.left.px]=\"\r\n isRtl() ? null : item().startOffsetPx + laneInsetPx()\r\n \"\r\n [style.right.px]=\"\r\n isRtl() ? item().startOffsetPx + laneInsetPx() : null\r\n \"\r\n [style.width.px]=\"item().trackWidthPx\"\r\n [style.background-color]=\"item().progressTrackColor\"\r\n [style.z-index]=\"1\"\r\n [attr.title]=\"item().progressLabel\"\r\n (click)=\"onProgressClick(item(), $event)\"\r\n >\r\n @if (item().progressFillWidthPx > 0) {\r\n <div\r\n class=\"h-full rounded-full\"\r\n [style.width.px]=\"item().progressFillWidthPx\"\r\n [style.min-width.px]=\"resolveProgressFillMinWidthPx(item())\"\r\n [style.background-color]=\"item().statusColor\"\r\n ></div>\r\n }\r\n\r\n @if (shouldRenderProgressLabel(item())) {\r\n <span\r\n class=\"pointer-events-none absolute top-1/2 z-[1] -translate-y-1/2 rounded-full bg-white px-2 py-0.5 text-[10px] font-semibold text-black shadow-sm\"\r\n [style.left.px]=\"isRtl() ? null : 8\"\r\n [style.right.px]=\"isRtl() ? 8 : null\"\r\n [attr.title]=\"item().progressLabel\"\r\n >\r\n {{ item().progressLabel }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n" }]
278
287
  }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], resolvedColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolvedColumns", required: false }] }], ganttCanvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttCanvasWidth", required: false }] }], laneInsetPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "laneInsetPx", required: false }] }], renderColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderColumns", required: false }] }], renderTimeline: [{ type: i0.Input, args: [{ isSignal: true, alias: "renderTimeline", required: false }] }], columnTemplatesByKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnTemplatesByKey", required: false }] }], progressTemplateDirective: [{ type: i0.Input, args: [{ isSignal: true, alias: "progressTemplateDirective", required: false }] }], toggleCollapse: [{ type: i0.Output, args: ["toggleCollapse"] }], progressClick: [{ type: i0.Output, args: ["progressClick"] }] } });
279
288
 
280
289
  /**
@@ -309,7 +318,6 @@ class TimelineGantt {
309
318
  splitterWidthPx = 10;
310
319
  timelineLaneInsetPx = 12;
311
320
  adaptiveSegmentMaxWidthPx = 320;
312
- laneInsetPx = this.timelineLaneInsetPx;
313
321
  columnsPaneUserWidthPx = signal(null, ...(ngDevMode ? [{ debugName: "columnsPaneUserWidthPx" }] : []));
314
322
  lastExpandedColumnsPaneWidthPx = signal(null, ...(ngDevMode ? [{ debugName: "lastExpandedColumnsPaneWidthPx" }] : []));
315
323
  isColumnsResizing = signal(false, ...(ngDevMode ? [{ debugName: "isColumnsResizing" }] : []));
@@ -327,6 +335,7 @@ class TimelineGantt {
327
335
  defaultVisibleColumns = input(4, ...(ngDevMode ? [{ debugName: "defaultVisibleColumns" }] : []));
328
336
  columnsPaneMinWidthPx = input(0, ...(ngDevMode ? [{ debugName: "columnsPaneMinWidthPx" }] : []));
329
337
  columnsPaneMaxWidthPx = input(null, ...(ngDevMode ? [{ debugName: "columnsPaneMaxWidthPx" }] : []));
338
+ zoomToFit = input(false, ...(ngDevMode ? [{ debugName: "zoomToFit" }] : []));
330
339
  mappedGanttNodes = input([], ...(ngDevMode ? [{ debugName: "mappedGanttNodes" }] : []));
331
340
  orderedGanttSegments = input([], ...(ngDevMode ? [{ debugName: "orderedGanttSegments" }] : []));
332
341
  collapsedGanttIds = input(new Set(), ...(ngDevMode ? [{ debugName: "collapsedGanttIds" }] : []));
@@ -399,9 +408,18 @@ class TimelineGantt {
399
408
  if (availableWidth <= 0) {
400
409
  return baseWidth;
401
410
  }
402
- const candidateWidth = Math.floor(availableWidth / segmentCount);
403
- return Math.max(baseWidth, Math.min(candidateWidth, this.adaptiveSegmentMaxWidthPx));
411
+ const candidateWidth = availableWidth / segmentCount;
412
+ if (this.zoomToFit()) {
413
+ return Math.max(0, Math.min(candidateWidth, this.adaptiveSegmentMaxWidthPx));
414
+ }
415
+ return Math.max(baseWidth, Math.min(Math.floor(candidateWidth), this.adaptiveSegmentMaxWidthPx));
404
416
  }, ...(ngDevMode ? [{ debugName: "effectiveGanttSegmentWidthPx" }] : []));
417
+ laneInsetPx = computed(() => {
418
+ if (!this.zoomToFit()) {
419
+ return this.timelineLaneInsetPx;
420
+ }
421
+ return Math.min(this.timelineLaneInsetPx, Math.max(0, this.effectiveGanttSegmentWidthPx() / 4));
422
+ }, ...(ngDevMode ? [{ debugName: "laneInsetPx" }] : []));
405
423
  ganttCanvasWidth = computed(() => this.orderedGanttSegments().length * this.effectiveGanttSegmentWidthPx(), ...(ngDevMode ? [{ debugName: "ganttCanvasWidth" }] : []));
406
424
  // Flattens the mapped hierarchy into rows using current collapse state.
407
425
  resolvedGanttItems = computed(() => {
@@ -616,7 +634,8 @@ class TimelineGantt {
616
634
  const normalizedEndSeq = Math.min(lastSeq, Math.max(startSeq, endSeq));
617
635
  const widthSegments = normalizedEndSeq - normalizedStartSeq + 1;
618
636
  const widthPx = Math.max(this.effectiveGanttSegmentWidthPx(), widthSegments * this.effectiveGanttSegmentWidthPx());
619
- const trackWidthPx = Math.max(0, widthPx - this.timelineLaneInsetPx * 2);
637
+ const laneInsetPx = this.laneInsetPx();
638
+ const trackWidthPx = Math.max(0, widthPx - laneInsetPx * 2);
620
639
  const progressValue = this.clampProgress(node.progress.value);
621
640
  const statusColor = this.resolveBaseColor(node.color ?? node.progress.color ?? null);
622
641
  return {
@@ -720,18 +739,23 @@ class TimelineGantt {
720
739
  return dir.toLowerCase() === 'rtl';
721
740
  }
722
741
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGantt, deps: [], target: i0.ɵɵFactoryTarget.Component });
723
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGantt, isStandalone: true, selector: "mt-timeline-gantt", inputs: { timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, ganttTitleColumnLabel: { classPropertyName: "ganttTitleColumnLabel", publicName: "ganttTitleColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnLabel: { classPropertyName: "ganttStatusColumnLabel", publicName: "ganttStatusColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttInitiativeColumnWidthPx: { classPropertyName: "ganttInitiativeColumnWidthPx", publicName: "ganttInitiativeColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnWidthPx: { classPropertyName: "ganttStatusColumnWidthPx", publicName: "ganttStatusColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, showGanttStatusColumn: { classPropertyName: "showGanttStatusColumn", publicName: "showGanttStatusColumn", isSignal: true, isRequired: false, transformFunction: null }, ganttSegmentWidthPx: { classPropertyName: "ganttSegmentWidthPx", publicName: "ganttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, defaultVisibleColumns: { classPropertyName: "defaultVisibleColumns", publicName: "defaultVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMinWidthPx: { classPropertyName: "columnsPaneMinWidthPx", publicName: "columnsPaneMinWidthPx", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMaxWidthPx: { classPropertyName: "columnsPaneMaxWidthPx", publicName: "columnsPaneMaxWidthPx", isSignal: true, isRequired: false, transformFunction: null }, mappedGanttNodes: { classPropertyName: "mappedGanttNodes", publicName: "mappedGanttNodes", isSignal: true, isRequired: false, transformFunction: null }, orderedGanttSegments: { classPropertyName: "orderedGanttSegments", publicName: "orderedGanttSegments", isSignal: true, isRequired: false, transformFunction: null }, collapsedGanttIds: { classPropertyName: "collapsedGanttIds", publicName: "collapsedGanttIds", isSignal: true, isRequired: false, transformFunction: null }, columnTemplatesByKey: { classPropertyName: "columnTemplatesByKey", publicName: "columnTemplatesByKey", isSignal: true, isRequired: false, transformFunction: null }, progressTemplateDirective: { classPropertyName: "progressTemplateDirective", publicName: "progressTemplateDirective", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleCollapse: "toggleCollapse", progressClick: "progressClick" }, viewQueries: [{ propertyName: "ganttSplitContainerRef", first: true, predicate: ["ganttSplitContainer"], descendants: true }, { propertyName: "ganttScrollViewportRef", first: true, predicate: ["ganttScrollViewport"], descendants: true }], ngImport: i0, template: "<!-- Gantt view shell: scroll viewport + sized timeline table. -->\n<div class=\"min-h-56 min-w-0 overflow-hidden py-2\">\n <div\n class=\"flex min-w-0 border border-surface bg-content\"\n #ganttSplitContainer\n >\n <!-- Fixed metadata columns pane. -->\n <div\n class=\"shrink-0 overflow-hidden\"\n [style.width.px]=\"resolvedColumnsPaneWidthPx()\"\n >\n <div class=\"mt-timeline-scroll h-full overflow-x-auto overflow-y-hidden\">\n <div class=\"min-w-full\" [style.width.px]=\"columnsContentWidthPx()\">\n <mt-timeline-gantt-header\n [timelineMode]=\"timelineMode()\"\n [resolvedColumns]=\"resolvedColumns()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [ganttCanvasWidth]=\"0\"\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\n [renderTimeline]=\"false\"\n />\n\n <div>\n @for (item of resolvedGanttItems(); track $index) {\n <mt-timeline-gantt-row\n [item]=\"item\"\n [resolvedColumns]=\"resolvedColumns()\"\n [ganttCanvasWidth]=\"0\"\n [laneInsetPx]=\"laneInsetPx\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplateDirective()\"\n [renderTimeline]=\"false\"\n (toggleCollapse)=\"onToggleCollapse($event)\"\n (progressClick)=\"onRowProgressClick($event)\"\n />\n }\n </div>\n </div>\n </div>\n </div>\n\n @if (canResizeColumnsPane()) {\n <button\n type=\"button\"\n class=\"mt-timeline-splitter shrink-0\"\n [class.mt-timeline-splitter-active]=\"isColumnsResizing()\"\n (pointerdown)=\"onSplitterPointerDown($event)\"\n (dblclick)=\"onSplitterDoubleClick()\"\n (keydown)=\"onSplitterKeyDown($event)\"\n aria-label=\"Resize columns pane\"\n title=\"Drag to resize. Double-click to collapse/restore.\"\n ></button>\n }\n\n <!-- Scrollable timeline pane (horizontal scroll is limited to this area). -->\n <div\n class=\"mt-timeline-scroll min-w-0 flex-1 overflow-x-auto overflow-y-hidden\"\n #ganttScrollViewport\n >\n <div class=\"min-w-full\" [style.width.px]=\"ganttCanvasWidth()\">\n <mt-timeline-gantt-header\n [timelineMode]=\"timelineMode()\"\n [resolvedColumns]=\"resolvedColumns()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\n [renderColumns]=\"false\"\n />\n\n <div>\n @for (item of resolvedGanttItems(); track $index) {\n <mt-timeline-gantt-row\n [item]=\"item\"\n [resolvedColumns]=\"[]\"\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\n [laneInsetPx]=\"laneInsetPx\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplateDirective()\"\n [renderColumns]=\"false\"\n (toggleCollapse)=\"onToggleCollapse($event)\"\n (progressClick)=\"onRowProgressClick($event)\"\n />\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;min-width:0;max-width:100%}.mt-timeline-scroll{min-width:0;scrollbar-width:thin;scrollbar-color:var(--p-surface-400) transparent}.mt-timeline-scroll::-webkit-scrollbar{height:10px}.mt-timeline-scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-200) 30%,transparent);border-radius:9999px}.mt-timeline-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-surface-500) 60%,transparent);border-radius:9999px;border:2px solid transparent;background-clip:content-box}.mt-timeline-scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-surface-600) 65%,transparent);background-clip:content-box}.mt-timeline-splitter{position:relative;width:10px;min-width:10px;border:0;overflow:visible;background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%);cursor:col-resize;touch-action:none;transition:background .14s ease,opacity .14s ease,filter .14s ease}.mt-timeline-splitter:hover,.mt-timeline-splitter-active,.mt-timeline-splitter:focus-visible{background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%)}.mt-timeline-splitter:before{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:16px;height:42px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;border:1px solid color-mix(in srgb,var(--p-surface-300) 72%,transparent);background:var(--p-surface-0);box-shadow:0 6px 16px -14px color-mix(in srgb,var(--p-surface-400) 18%,transparent),0 2px 6px -4px color-mix(in srgb,black 16%,transparent);pointer-events:none;transition:opacity .14s ease,transform .14s ease,border-color .14s ease,box-shadow .14s ease}.mt-timeline-splitter:after{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:6px;height:16px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;background:linear-gradient(90deg,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 0,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 6px);pointer-events:none;transition:opacity .14s ease,transform .14s ease,background .14s ease}.mt-timeline-splitter:hover:before,.mt-timeline-splitter-active:before,.mt-timeline-splitter:focus-visible:before{border-color:color-mix(in srgb,var(--p-primary-color) 18%,var(--p-surface-200));box-shadow:0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}.mt-timeline-splitter:hover:after,.mt-timeline-splitter-active:after,.mt-timeline-splitter:focus-visible:after{background:linear-gradient(90deg,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 0,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 6px)}.mt-timeline-splitter:hover{filter:saturate(1.03)}.mt-timeline-splitter:focus-visible{outline:none}.mt-timeline-splitter:focus-visible:before{box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color) 14%,transparent),0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TimelineGanttHeader, selector: "mt-timeline-gantt-header", inputs: ["timelineMode", "resolvedColumns", "orderedGanttSegments", "ganttCanvasWidth", "effectiveGanttSegmentWidthPx", "renderColumns", "renderTimeline"] }, { kind: "component", type: TimelineGanttRow, selector: "mt-timeline-gantt-row", inputs: ["item", "resolvedColumns", "ganttCanvasWidth", "laneInsetPx", "renderColumns", "renderTimeline", "columnTemplatesByKey", "progressTemplateDirective"], outputs: ["toggleCollapse", "progressClick"] }] });
742
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineGantt, isStandalone: true, selector: "mt-timeline-gantt", inputs: { timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, ganttTitleColumnLabel: { classPropertyName: "ganttTitleColumnLabel", publicName: "ganttTitleColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnLabel: { classPropertyName: "ganttStatusColumnLabel", publicName: "ganttStatusColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttInitiativeColumnWidthPx: { classPropertyName: "ganttInitiativeColumnWidthPx", publicName: "ganttInitiativeColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnWidthPx: { classPropertyName: "ganttStatusColumnWidthPx", publicName: "ganttStatusColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, showGanttStatusColumn: { classPropertyName: "showGanttStatusColumn", publicName: "showGanttStatusColumn", isSignal: true, isRequired: false, transformFunction: null }, ganttSegmentWidthPx: { classPropertyName: "ganttSegmentWidthPx", publicName: "ganttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, defaultVisibleColumns: { classPropertyName: "defaultVisibleColumns", publicName: "defaultVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMinWidthPx: { classPropertyName: "columnsPaneMinWidthPx", publicName: "columnsPaneMinWidthPx", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMaxWidthPx: { classPropertyName: "columnsPaneMaxWidthPx", publicName: "columnsPaneMaxWidthPx", isSignal: true, isRequired: false, transformFunction: null }, zoomToFit: { classPropertyName: "zoomToFit", publicName: "zoomToFit", isSignal: true, isRequired: false, transformFunction: null }, mappedGanttNodes: { classPropertyName: "mappedGanttNodes", publicName: "mappedGanttNodes", isSignal: true, isRequired: false, transformFunction: null }, orderedGanttSegments: { classPropertyName: "orderedGanttSegments", publicName: "orderedGanttSegments", isSignal: true, isRequired: false, transformFunction: null }, collapsedGanttIds: { classPropertyName: "collapsedGanttIds", publicName: "collapsedGanttIds", isSignal: true, isRequired: false, transformFunction: null }, columnTemplatesByKey: { classPropertyName: "columnTemplatesByKey", publicName: "columnTemplatesByKey", isSignal: true, isRequired: false, transformFunction: null }, progressTemplateDirective: { classPropertyName: "progressTemplateDirective", publicName: "progressTemplateDirective", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleCollapse: "toggleCollapse", progressClick: "progressClick" }, viewQueries: [{ propertyName: "ganttSplitContainerRef", first: true, predicate: ["ganttSplitContainer"], descendants: true }, { propertyName: "ganttScrollViewportRef", first: true, predicate: ["ganttScrollViewport"], descendants: true }], ngImport: i0, template: "<!-- Gantt view shell: scroll viewport + sized timeline table. -->\r\n<div\r\n class=\"min-h-56 min-w-0 overflow-hidden py-2\"\r\n *transloco=\"let t; prefix: 'timeline'\"\r\n>\r\n <div\r\n class=\"flex min-w-0 border border-surface bg-content\"\r\n #ganttSplitContainer\r\n >\r\n <!-- Fixed metadata columns pane. -->\r\n <div\r\n class=\"shrink-0 overflow-hidden\"\r\n [style.width.px]=\"resolvedColumnsPaneWidthPx()\"\r\n >\r\n <div class=\"mt-timeline-scroll h-full overflow-x-auto overflow-y-hidden\">\r\n <div class=\"min-w-full\" [style.width.px]=\"columnsContentWidthPx()\">\r\n <mt-timeline-gantt-header\r\n [timelineMode]=\"timelineMode()\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [ganttCanvasWidth]=\"0\"\r\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [renderTimeline]=\"false\"\r\n />\r\n\r\n <div>\r\n @for (item of resolvedGanttItems(); track $index) {\r\n <mt-timeline-gantt-row\r\n [item]=\"item\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [ganttCanvasWidth]=\"0\"\r\n [laneInsetPx]=\"laneInsetPx()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplateDirective()\"\r\n [renderTimeline]=\"false\"\r\n (toggleCollapse)=\"onToggleCollapse($event)\"\r\n (progressClick)=\"onRowProgressClick($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (canResizeColumnsPane()) {\r\n <button\r\n type=\"button\"\r\n class=\"mt-timeline-splitter shrink-0\"\r\n [class.mt-timeline-splitter-active]=\"isColumnsResizing()\"\r\n (pointerdown)=\"onSplitterPointerDown($event)\"\r\n (dblclick)=\"onSplitterDoubleClick()\"\r\n (keydown)=\"onSplitterKeyDown($event)\"\r\n [attr.aria-label]=\"t('resize-columns')\"\r\n [title]=\"t('resize-columns-hint')\"\r\n ></button>\r\n }\r\n\r\n <!-- Scrollable timeline pane (horizontal scroll is limited to this area). -->\r\n <div\r\n class=\"mt-timeline-scroll min-w-0 flex-1 overflow-x-auto overflow-y-hidden\"\r\n #ganttScrollViewport\r\n >\r\n <div class=\"min-w-full\" [style.width.px]=\"ganttCanvasWidth()\">\r\n <mt-timeline-gantt-header\r\n [timelineMode]=\"timelineMode()\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\r\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [renderColumns]=\"false\"\r\n />\r\n\r\n <div>\r\n @for (item of resolvedGanttItems(); track $index) {\r\n <mt-timeline-gantt-row\r\n [item]=\"item\"\r\n [resolvedColumns]=\"[]\"\r\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\r\n [laneInsetPx]=\"laneInsetPx()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplateDirective()\"\r\n [renderColumns]=\"false\"\r\n (toggleCollapse)=\"onToggleCollapse($event)\"\r\n (progressClick)=\"onRowProgressClick($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;min-width:0;max-width:100%}.mt-timeline-scroll{min-width:0;scrollbar-width:thin;scrollbar-color:var(--p-surface-400) transparent}.mt-timeline-scroll::-webkit-scrollbar{height:10px}.mt-timeline-scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-200) 30%,transparent);border-radius:9999px}.mt-timeline-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-surface-500) 60%,transparent);border-radius:9999px;border:2px solid transparent;background-clip:content-box}.mt-timeline-scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-surface-600) 65%,transparent);background-clip:content-box}.mt-timeline-splitter{position:relative;width:10px;min-width:10px;border:0;overflow:visible;background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%);cursor:col-resize;touch-action:none;transition:background .14s ease,opacity .14s ease,filter .14s ease}.mt-timeline-splitter:hover,.mt-timeline-splitter-active,.mt-timeline-splitter:focus-visible{background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%)}.mt-timeline-splitter:before{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:16px;height:42px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;border:1px solid color-mix(in srgb,var(--p-surface-300) 72%,transparent);background:var(--p-surface-0);box-shadow:0 6px 16px -14px color-mix(in srgb,var(--p-surface-400) 18%,transparent),0 2px 6px -4px color-mix(in srgb,black 16%,transparent);pointer-events:none;transition:opacity .14s ease,transform .14s ease,border-color .14s ease,box-shadow .14s ease}.mt-timeline-splitter:after{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:6px;height:16px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;background:linear-gradient(90deg,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 0,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 6px);pointer-events:none;transition:opacity .14s ease,transform .14s ease,background .14s ease}.mt-timeline-splitter:hover:before,.mt-timeline-splitter-active:before,.mt-timeline-splitter:focus-visible:before{border-color:color-mix(in srgb,var(--p-primary-color) 18%,var(--p-surface-200));box-shadow:0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}.mt-timeline-splitter:hover:after,.mt-timeline-splitter-active:after,.mt-timeline-splitter:focus-visible:after{background:linear-gradient(90deg,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 0,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 6px)}.mt-timeline-splitter:hover{filter:saturate(1.03)}.mt-timeline-splitter:focus-visible{outline:none}.mt-timeline-splitter:focus-visible:before{box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color) 14%,transparent),0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: TimelineGanttHeader, selector: "mt-timeline-gantt-header", inputs: ["timelineMode", "resolvedColumns", "orderedGanttSegments", "ganttCanvasWidth", "effectiveGanttSegmentWidthPx", "zoomToFit", "renderColumns", "renderTimeline"] }, { kind: "component", type: TimelineGanttRow, selector: "mt-timeline-gantt-row", inputs: ["item", "resolvedColumns", "ganttCanvasWidth", "laneInsetPx", "renderColumns", "renderTimeline", "columnTemplatesByKey", "progressTemplateDirective"], outputs: ["toggleCollapse", "progressClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
724
743
  }
725
744
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineGantt, decorators: [{
726
745
  type: Component,
727
- args: [{ selector: 'mt-timeline-gantt', standalone: true, imports: [CommonModule, TimelineGanttHeader, TimelineGanttRow], template: "<!-- Gantt view shell: scroll viewport + sized timeline table. -->\n<div class=\"min-h-56 min-w-0 overflow-hidden py-2\">\n <div\n class=\"flex min-w-0 border border-surface bg-content\"\n #ganttSplitContainer\n >\n <!-- Fixed metadata columns pane. -->\n <div\n class=\"shrink-0 overflow-hidden\"\n [style.width.px]=\"resolvedColumnsPaneWidthPx()\"\n >\n <div class=\"mt-timeline-scroll h-full overflow-x-auto overflow-y-hidden\">\n <div class=\"min-w-full\" [style.width.px]=\"columnsContentWidthPx()\">\n <mt-timeline-gantt-header\n [timelineMode]=\"timelineMode()\"\n [resolvedColumns]=\"resolvedColumns()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [ganttCanvasWidth]=\"0\"\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\n [renderTimeline]=\"false\"\n />\n\n <div>\n @for (item of resolvedGanttItems(); track $index) {\n <mt-timeline-gantt-row\n [item]=\"item\"\n [resolvedColumns]=\"resolvedColumns()\"\n [ganttCanvasWidth]=\"0\"\n [laneInsetPx]=\"laneInsetPx\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplateDirective()\"\n [renderTimeline]=\"false\"\n (toggleCollapse)=\"onToggleCollapse($event)\"\n (progressClick)=\"onRowProgressClick($event)\"\n />\n }\n </div>\n </div>\n </div>\n </div>\n\n @if (canResizeColumnsPane()) {\n <button\n type=\"button\"\n class=\"mt-timeline-splitter shrink-0\"\n [class.mt-timeline-splitter-active]=\"isColumnsResizing()\"\n (pointerdown)=\"onSplitterPointerDown($event)\"\n (dblclick)=\"onSplitterDoubleClick()\"\n (keydown)=\"onSplitterKeyDown($event)\"\n aria-label=\"Resize columns pane\"\n title=\"Drag to resize. Double-click to collapse/restore.\"\n ></button>\n }\n\n <!-- Scrollable timeline pane (horizontal scroll is limited to this area). -->\n <div\n class=\"mt-timeline-scroll min-w-0 flex-1 overflow-x-auto overflow-y-hidden\"\n #ganttScrollViewport\n >\n <div class=\"min-w-full\" [style.width.px]=\"ganttCanvasWidth()\">\n <mt-timeline-gantt-header\n [timelineMode]=\"timelineMode()\"\n [resolvedColumns]=\"resolvedColumns()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\n [renderColumns]=\"false\"\n />\n\n <div>\n @for (item of resolvedGanttItems(); track $index) {\n <mt-timeline-gantt-row\n [item]=\"item\"\n [resolvedColumns]=\"[]\"\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\n [laneInsetPx]=\"laneInsetPx\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplateDirective()\"\n [renderColumns]=\"false\"\n (toggleCollapse)=\"onToggleCollapse($event)\"\n (progressClick)=\"onRowProgressClick($event)\"\n />\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;min-width:0;max-width:100%}.mt-timeline-scroll{min-width:0;scrollbar-width:thin;scrollbar-color:var(--p-surface-400) transparent}.mt-timeline-scroll::-webkit-scrollbar{height:10px}.mt-timeline-scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-200) 30%,transparent);border-radius:9999px}.mt-timeline-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-surface-500) 60%,transparent);border-radius:9999px;border:2px solid transparent;background-clip:content-box}.mt-timeline-scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-surface-600) 65%,transparent);background-clip:content-box}.mt-timeline-splitter{position:relative;width:10px;min-width:10px;border:0;overflow:visible;background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%);cursor:col-resize;touch-action:none;transition:background .14s ease,opacity .14s ease,filter .14s ease}.mt-timeline-splitter:hover,.mt-timeline-splitter-active,.mt-timeline-splitter:focus-visible{background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%)}.mt-timeline-splitter:before{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:16px;height:42px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;border:1px solid color-mix(in srgb,var(--p-surface-300) 72%,transparent);background:var(--p-surface-0);box-shadow:0 6px 16px -14px color-mix(in srgb,var(--p-surface-400) 18%,transparent),0 2px 6px -4px color-mix(in srgb,black 16%,transparent);pointer-events:none;transition:opacity .14s ease,transform .14s ease,border-color .14s ease,box-shadow .14s ease}.mt-timeline-splitter:after{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:6px;height:16px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;background:linear-gradient(90deg,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 0,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 6px);pointer-events:none;transition:opacity .14s ease,transform .14s ease,background .14s ease}.mt-timeline-splitter:hover:before,.mt-timeline-splitter-active:before,.mt-timeline-splitter:focus-visible:before{border-color:color-mix(in srgb,var(--p-primary-color) 18%,var(--p-surface-200));box-shadow:0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}.mt-timeline-splitter:hover:after,.mt-timeline-splitter-active:after,.mt-timeline-splitter:focus-visible:after{background:linear-gradient(90deg,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 0,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 6px)}.mt-timeline-splitter:hover{filter:saturate(1.03)}.mt-timeline-splitter:focus-visible{outline:none}.mt-timeline-splitter:focus-visible:before{box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color) 14%,transparent),0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}\n"] }]
746
+ args: [{ selector: 'mt-timeline-gantt', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
747
+ CommonModule,
748
+ TranslocoDirective,
749
+ TimelineGanttHeader,
750
+ TimelineGanttRow,
751
+ ], template: "<!-- Gantt view shell: scroll viewport + sized timeline table. -->\r\n<div\r\n class=\"min-h-56 min-w-0 overflow-hidden py-2\"\r\n *transloco=\"let t; prefix: 'timeline'\"\r\n>\r\n <div\r\n class=\"flex min-w-0 border border-surface bg-content\"\r\n #ganttSplitContainer\r\n >\r\n <!-- Fixed metadata columns pane. -->\r\n <div\r\n class=\"shrink-0 overflow-hidden\"\r\n [style.width.px]=\"resolvedColumnsPaneWidthPx()\"\r\n >\r\n <div class=\"mt-timeline-scroll h-full overflow-x-auto overflow-y-hidden\">\r\n <div class=\"min-w-full\" [style.width.px]=\"columnsContentWidthPx()\">\r\n <mt-timeline-gantt-header\r\n [timelineMode]=\"timelineMode()\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [ganttCanvasWidth]=\"0\"\r\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [renderTimeline]=\"false\"\r\n />\r\n\r\n <div>\r\n @for (item of resolvedGanttItems(); track $index) {\r\n <mt-timeline-gantt-row\r\n [item]=\"item\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [ganttCanvasWidth]=\"0\"\r\n [laneInsetPx]=\"laneInsetPx()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplateDirective()\"\r\n [renderTimeline]=\"false\"\r\n (toggleCollapse)=\"onToggleCollapse($event)\"\r\n (progressClick)=\"onRowProgressClick($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (canResizeColumnsPane()) {\r\n <button\r\n type=\"button\"\r\n class=\"mt-timeline-splitter shrink-0\"\r\n [class.mt-timeline-splitter-active]=\"isColumnsResizing()\"\r\n (pointerdown)=\"onSplitterPointerDown($event)\"\r\n (dblclick)=\"onSplitterDoubleClick()\"\r\n (keydown)=\"onSplitterKeyDown($event)\"\r\n [attr.aria-label]=\"t('resize-columns')\"\r\n [title]=\"t('resize-columns-hint')\"\r\n ></button>\r\n }\r\n\r\n <!-- Scrollable timeline pane (horizontal scroll is limited to this area). -->\r\n <div\r\n class=\"mt-timeline-scroll min-w-0 flex-1 overflow-x-auto overflow-y-hidden\"\r\n #ganttScrollViewport\r\n >\r\n <div class=\"min-w-full\" [style.width.px]=\"ganttCanvasWidth()\">\r\n <mt-timeline-gantt-header\r\n [timelineMode]=\"timelineMode()\"\r\n [resolvedColumns]=\"resolvedColumns()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\r\n [effectiveGanttSegmentWidthPx]=\"effectiveGanttSegmentWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [renderColumns]=\"false\"\r\n />\r\n\r\n <div>\r\n @for (item of resolvedGanttItems(); track $index) {\r\n <mt-timeline-gantt-row\r\n [item]=\"item\"\r\n [resolvedColumns]=\"[]\"\r\n [ganttCanvasWidth]=\"ganttCanvasWidth()\"\r\n [laneInsetPx]=\"laneInsetPx()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplateDirective()\"\r\n [renderColumns]=\"false\"\r\n (toggleCollapse)=\"onToggleCollapse($event)\"\r\n (progressClick)=\"onRowProgressClick($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;min-width:0;max-width:100%}.mt-timeline-scroll{min-width:0;scrollbar-width:thin;scrollbar-color:var(--p-surface-400) transparent}.mt-timeline-scroll::-webkit-scrollbar{height:10px}.mt-timeline-scroll::-webkit-scrollbar-track{background:color-mix(in srgb,var(--p-surface-200) 30%,transparent);border-radius:9999px}.mt-timeline-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--p-surface-500) 60%,transparent);border-radius:9999px;border:2px solid transparent;background-clip:content-box}.mt-timeline-scroll::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--p-surface-600) 65%,transparent);background-clip:content-box}.mt-timeline-splitter{position:relative;width:10px;min-width:10px;border:0;overflow:visible;background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-surface-300) 45%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% - 1px),color-mix(in srgb,var(--p-surface-500) 72%,white 28%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%);cursor:col-resize;touch-action:none;transition:background .14s ease,opacity .14s ease,filter .14s ease}.mt-timeline-splitter:hover,.mt-timeline-splitter-active,.mt-timeline-splitter:focus-visible{background:linear-gradient(90deg,transparent 0,transparent calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% - 4px),color-mix(in srgb,var(--p-primary-color) 22%,transparent) calc(50% + 4px),transparent calc(50% + 4px),transparent 100%),linear-gradient(90deg,transparent 0,transparent calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% - 1px),color-mix(in srgb,var(--p-primary-color) 88%,white 12%) calc(50% + 1px),transparent calc(50% + 1px),transparent 100%)}.mt-timeline-splitter:before{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:16px;height:42px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;border:1px solid color-mix(in srgb,var(--p-surface-300) 72%,transparent);background:var(--p-surface-0);box-shadow:0 6px 16px -14px color-mix(in srgb,var(--p-surface-400) 18%,transparent),0 2px 6px -4px color-mix(in srgb,black 16%,transparent);pointer-events:none;transition:opacity .14s ease,transform .14s ease,border-color .14s ease,box-shadow .14s ease}.mt-timeline-splitter:after{content:\"\";position:absolute;top:50%;inset-inline-start:50%;width:6px;height:16px;transform:translate(-50%,-50%) scale(1);opacity:1;border-radius:9999px;background:linear-gradient(90deg,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 0,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 4px,color-mix(in srgb,var(--p-surface-500) 78%,white 22%) 6px);pointer-events:none;transition:opacity .14s ease,transform .14s ease,background .14s ease}.mt-timeline-splitter:hover:before,.mt-timeline-splitter-active:before,.mt-timeline-splitter:focus-visible:before{border-color:color-mix(in srgb,var(--p-primary-color) 18%,var(--p-surface-200));box-shadow:0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}.mt-timeline-splitter:hover:after,.mt-timeline-splitter-active:after,.mt-timeline-splitter:focus-visible:after{background:linear-gradient(90deg,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 0,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 2px,transparent 2px,transparent 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 4px,color-mix(in srgb,var(--p-primary-color) 88%,white 12%) 6px)}.mt-timeline-splitter:hover{filter:saturate(1.03)}.mt-timeline-splitter:focus-visible{outline:none}.mt-timeline-splitter:focus-visible:before{box-shadow:0 0 0 3px color-mix(in srgb,var(--p-primary-color) 14%,transparent),0 8px 18px -16px color-mix(in srgb,var(--p-primary-color) 28%,transparent),0 4px 8px -6px color-mix(in srgb,black 18%,transparent)}\n"] }]
728
752
  }], propDecorators: { ganttSplitContainerRef: [{
729
753
  type: ViewChild,
730
754
  args: ['ganttSplitContainer']
731
755
  }], ganttScrollViewportRef: [{
732
756
  type: ViewChild,
733
757
  args: ['ganttScrollViewport']
734
- }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], ganttTitleColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttTitleColumnLabel", required: false }] }], ganttStatusColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnLabel", required: false }] }], ganttInitiativeColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttInitiativeColumnWidthPx", required: false }] }], ganttStatusColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnWidthPx", required: false }] }], showGanttStatusColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttStatusColumn", required: false }] }], ganttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttSegmentWidthPx", required: false }] }], defaultVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultVisibleColumns", required: false }] }], columnsPaneMinWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMinWidthPx", required: false }] }], columnsPaneMaxWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMaxWidthPx", required: false }] }], mappedGanttNodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "mappedGanttNodes", required: false }] }], orderedGanttSegments: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderedGanttSegments", required: false }] }], collapsedGanttIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedGanttIds", required: false }] }], columnTemplatesByKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnTemplatesByKey", required: false }] }], progressTemplateDirective: [{ type: i0.Input, args: [{ isSignal: true, alias: "progressTemplateDirective", required: false }] }], toggleCollapse: [{ type: i0.Output, args: ["toggleCollapse"] }], progressClick: [{ type: i0.Output, args: ["progressClick"] }] } });
758
+ }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], ganttTitleColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttTitleColumnLabel", required: false }] }], ganttStatusColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnLabel", required: false }] }], ganttInitiativeColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttInitiativeColumnWidthPx", required: false }] }], ganttStatusColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnWidthPx", required: false }] }], showGanttStatusColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttStatusColumn", required: false }] }], ganttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttSegmentWidthPx", required: false }] }], defaultVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultVisibleColumns", required: false }] }], columnsPaneMinWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMinWidthPx", required: false }] }], columnsPaneMaxWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMaxWidthPx", required: false }] }], zoomToFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomToFit", required: false }] }], mappedGanttNodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "mappedGanttNodes", required: false }] }], orderedGanttSegments: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderedGanttSegments", required: false }] }], collapsedGanttIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedGanttIds", required: false }] }], columnTemplatesByKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnTemplatesByKey", required: false }] }], progressTemplateDirective: [{ type: i0.Input, args: [{ isSignal: true, alias: "progressTemplateDirective", required: false }] }], toggleCollapse: [{ type: i0.Output, args: ["toggleCollapse"] }], progressClick: [{ type: i0.Output, args: ["progressClick"] }] } });
735
759
 
736
760
  /**
737
761
  * Shared timeline header.
@@ -745,28 +769,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
745
769
  * the parent timeline container.
746
770
  */
747
771
  class TimelineHeader {
748
- title = input('Timeline', ...(ngDevMode ? [{ debugName: "title" }] : []));
772
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
749
773
  timelineMode = input('quarterly', ...(ngDevMode ? [{ debugName: "timelineMode" }] : []));
750
774
  timelineModeOptions = input([], ...(ngDevMode ? [{ debugName: "timelineModeOptions" }] : []));
775
+ showZoomToFitControl = input(false, ...(ngDevMode ? [{ debugName: "showZoomToFitControl" }] : []));
776
+ zoomToFit = input(false, ...(ngDevMode ? [{ debugName: "zoomToFit" }] : []));
777
+ zoomToFitDisabled = input(false, ...(ngDevMode ? [{ debugName: "zoomToFitDisabled" }] : []));
751
778
  timelineModeChange = output();
779
+ zoomToFitToggle = output();
752
780
  // Re-emits selector changes so parent owns state updates.
753
781
  onTimelineModeChange(mode) {
754
782
  this.timelineModeChange.emit(mode);
755
783
  }
784
+ onZoomToFitToggle() {
785
+ if (this.zoomToFitDisabled()) {
786
+ return;
787
+ }
788
+ this.zoomToFitToggle.emit();
789
+ }
790
+ getZoomToFitTooltip() {
791
+ return this.zoomToFit() ? 'Disable zoom to fit' : 'Zoom to fit';
792
+ }
756
793
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
757
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: TimelineHeader, isStandalone: true, selector: "mt-timeline-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, timelineModeOptions: { classPropertyName: "timelineModeOptions", publicName: "timelineModeOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timelineModeChange: "timelineModeChange" }, ngImport: i0, template: "<!-- Timeline title + scale mode selector. -->\r\n<div class=\"flex flex-wrap items-center justify-between gap-3\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-icon icon=\"custom.timeline-point\" class=\"text-base\"></mt-icon>\r\n <h3 class=\"text-base font-semibold\">{{ title() }}</h3>\r\n </div>\r\n\r\n <!-- Scale mode switcher (monthly/quarterly/etc.). -->\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n <div class=\"w-44\">\r\n <mt-select-field\r\n [field]=\"false\"\r\n [options]=\"timelineModeOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [showClear]=\"false\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n placeholder=\"Timeline mode\"\r\n [ngModel]=\"timelineMode()\"\r\n (onChange)=\"onTimelineModeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }] });
794
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: TimelineHeader, isStandalone: true, selector: "mt-timeline-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, timelineModeOptions: { classPropertyName: "timelineModeOptions", publicName: "timelineModeOptions", isSignal: true, isRequired: false, transformFunction: null }, showZoomToFitControl: { classPropertyName: "showZoomToFitControl", publicName: "showZoomToFitControl", isSignal: true, isRequired: false, transformFunction: null }, zoomToFit: { classPropertyName: "zoomToFit", publicName: "zoomToFit", isSignal: true, isRequired: false, transformFunction: null }, zoomToFitDisabled: { classPropertyName: "zoomToFitDisabled", publicName: "zoomToFitDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timelineModeChange: "timelineModeChange", zoomToFitToggle: "zoomToFitToggle" }, ngImport: i0, template: "<!-- Timeline title + scale mode selector. -->\r\n<div\r\n class=\"flex flex-wrap items-center justify-between gap-3\"\r\n *transloco=\"let t; prefix: 'timeline'\"\r\n>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-icon icon=\"custom.timeline-point\" class=\"text-base\"></mt-icon>\r\n <h3 class=\"text-base font-semibold\">{{ title() || t(\"timeline\") }}</h3>\r\n </div>\r\n\r\n <!-- Scale mode switcher (monthly/quarterly/etc.). -->\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n @if (showZoomToFitControl()) {\r\n <mt-button\r\n class=\"shrink-0\"\r\n type=\"button\"\r\n icon=\"layout.maximize-01\"\r\n size=\"large\"\r\n [tooltip]=\"getZoomToFitTooltip()\"\r\n [severity]=\"zoomToFit() ? 'primary' : 'secondary'\"\r\n [outlined]=\"!zoomToFit()\"\r\n [disabled]=\"zoomToFitDisabled()\"\r\n (onClick)=\"onZoomToFitToggle()\"\r\n />\r\n }\r\n\r\n <div class=\"w-44\">\r\n <mt-select-field\r\n [field]=\"false\"\r\n [options]=\"timelineModeOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [showClear]=\"false\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('timeline-mode')\"\r\n [ngModel]=\"timelineMode()\"\r\n (onChange)=\"onTimelineModeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
758
795
  }
759
796
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: TimelineHeader, decorators: [{
760
797
  type: Component,
761
- args: [{ selector: 'mt-timeline-header', standalone: true, imports: [FormsModule, SelectField, Icon], template: "<!-- Timeline title + scale mode selector. -->\r\n<div class=\"flex flex-wrap items-center justify-between gap-3\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-icon icon=\"custom.timeline-point\" class=\"text-base\"></mt-icon>\r\n <h3 class=\"text-base font-semibold\">{{ title() }}</h3>\r\n </div>\r\n\r\n <!-- Scale mode switcher (monthly/quarterly/etc.). -->\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n <div class=\"w-44\">\r\n <mt-select-field\r\n [field]=\"false\"\r\n [options]=\"timelineModeOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [showClear]=\"false\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n placeholder=\"Timeline mode\"\r\n [ngModel]=\"timelineMode()\"\r\n (onChange)=\"onTimelineModeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n" }]
762
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], timelineModeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineModeOptions", required: false }] }], timelineModeChange: [{ type: i0.Output, args: ["timelineModeChange"] }] } });
798
+ args: [{ selector: 'mt-timeline-header', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, Button, TranslocoDirective, SelectField, Icon], template: "<!-- Timeline title + scale mode selector. -->\r\n<div\r\n class=\"flex flex-wrap items-center justify-between gap-3\"\r\n *transloco=\"let t; prefix: 'timeline'\"\r\n>\r\n <div class=\"flex items-center gap-2\">\r\n <mt-icon icon=\"custom.timeline-point\" class=\"text-base\"></mt-icon>\r\n <h3 class=\"text-base font-semibold\">{{ title() || t(\"timeline\") }}</h3>\r\n </div>\r\n\r\n <!-- Scale mode switcher (monthly/quarterly/etc.). -->\r\n <div class=\"flex flex-wrap items-center justify-end gap-2\">\r\n @if (showZoomToFitControl()) {\r\n <mt-button\r\n class=\"shrink-0\"\r\n type=\"button\"\r\n icon=\"layout.maximize-01\"\r\n size=\"large\"\r\n [tooltip]=\"getZoomToFitTooltip()\"\r\n [severity]=\"zoomToFit() ? 'primary' : 'secondary'\"\r\n [outlined]=\"!zoomToFit()\"\r\n [disabled]=\"zoomToFitDisabled()\"\r\n (onClick)=\"onZoomToFitToggle()\"\r\n />\r\n }\r\n\r\n <div class=\"w-44\">\r\n <mt-select-field\r\n [field]=\"false\"\r\n [options]=\"timelineModeOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [showClear]=\"false\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('timeline-mode')\"\r\n [ngModel]=\"timelineMode()\"\r\n (onChange)=\"onTimelineModeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n" }]
799
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }], timelineModeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineModeOptions", required: false }] }], showZoomToFitControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "showZoomToFitControl", required: false }] }], zoomToFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomToFit", required: false }] }], zoomToFitDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomToFitDisabled", required: false }] }], timelineModeChange: [{ type: i0.Output, args: ["timelineModeChange"] }], zoomToFitToggle: [{ type: i0.Output, args: ["zoomToFitToggle"] }] } });
763
800
 
764
- // Default scale options shown in the timeline mode dropdown.
765
- const DEFAULT_TIMELINE_MODES = [
766
- { label: 'Monthly', value: 'monthly' },
767
- { label: 'Quarterly', value: 'quarterly' },
768
- { label: 'Semi Annual', value: 'biannually' },
769
- { label: 'Annually', value: 'annually' },
801
+ // Default scale mode values (labels are resolved at runtime via i18n).
802
+ const DEFAULT_TIMELINE_MODE_VALUES = [
803
+ 'monthly',
804
+ 'quarterly',
805
+ 'biannually',
806
+ 'annually',
770
807
  ];
771
808
  /**
772
809
  * Dynamic Gantt timeline component.
@@ -787,14 +824,27 @@ class Timeline {
787
824
  detailsPopover;
788
825
  // Invisible anchor used to position popover at exact mouse click coordinates.
789
826
  detailsPopoverClickAnchor;
790
- title = input('Timeline', ...(ngDevMode ? [{ debugName: "title" }] : []));
791
- emptyMessage = input('No data to display', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
827
+ transloco = inject(TranslocoService);
828
+ destroyRef = inject(DestroyRef);
829
+ activeLang = signal(this.transloco.getActiveLang(), ...(ngDevMode ? [{ debugName: "activeLang" }] : []));
830
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
831
+ emptyMessage = input('', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
792
832
  isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
793
833
  showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
834
+ showZoomToFitControl = input(false, ...(ngDevMode ? [{ debugName: "showZoomToFitControl" }] : []));
794
835
  timelineMode = model('quarterly', ...(ngDevMode ? [{ debugName: "timelineMode" }] : []));
795
- timelineModeOptions = input([
796
- ...DEFAULT_TIMELINE_MODES,
797
- ], ...(ngDevMode ? [{ debugName: "timelineModeOptions" }] : []));
836
+ timelineModeOptions = input([], ...(ngDevMode ? [{ debugName: "timelineModeOptions" }] : []));
837
+ resolvedTimelineModeOptions = computed(() => {
838
+ const options = this.timelineModeOptions();
839
+ if (options.length)
840
+ return options;
841
+ this.activeLang(); // reactive dependency for language changes
842
+ return DEFAULT_TIMELINE_MODE_VALUES.map((value) => ({
843
+ label: this.transloco.translate(`timeline.mode-${value}`),
844
+ value,
845
+ }));
846
+ }, ...(ngDevMode ? [{ debugName: "resolvedTimelineModeOptions" }] : []));
847
+ zoomToFit = model(false, ...(ngDevMode ? [{ debugName: "zoomToFit" }] : []));
798
848
  ganttData = input([], ...(ngDevMode ? [{ debugName: "ganttData" }] : []));
799
849
  ganttMapping = input(null, ...(ngDevMode ? [{ debugName: "ganttMapping" }] : []));
800
850
  // Null means "legacy defaults". Empty array means "progress-only" mode.
@@ -804,8 +854,8 @@ class Timeline {
804
854
  columnsPaneMinWidthPx = input(0, ...(ngDevMode ? [{ debugName: "columnsPaneMinWidthPx" }] : []));
805
855
  columnsPaneMaxWidthPx = input(null, ...(ngDevMode ? [{ debugName: "columnsPaneMaxWidthPx" }] : []));
806
856
  // Backward-compatible defaults when `columns` is null.
807
- ganttTitleColumnLabel = input('Portfolio Name', ...(ngDevMode ? [{ debugName: "ganttTitleColumnLabel" }] : []));
808
- ganttStatusColumnLabel = input('Status', ...(ngDevMode ? [{ debugName: "ganttStatusColumnLabel" }] : []));
857
+ ganttTitleColumnLabel = input('', ...(ngDevMode ? [{ debugName: "ganttTitleColumnLabel" }] : []));
858
+ ganttStatusColumnLabel = input('', ...(ngDevMode ? [{ debugName: "ganttStatusColumnLabel" }] : []));
809
859
  ganttInitiativeColumnWidthPx = input(288, ...(ngDevMode ? [{ debugName: "ganttInitiativeColumnWidthPx" }] : []));
810
860
  ganttStatusColumnWidthPx = input(160, ...(ngDevMode ? [{ debugName: "ganttStatusColumnWidthPx" }] : []));
811
861
  showGanttStatusColumn = input(false, ...(ngDevMode ? [{ debugName: "showGanttStatusColumn" }] : []));
@@ -856,6 +906,12 @@ class Timeline {
856
906
  }
857
907
  return this.buildSegments(range.startAt, range.endAt, this.timelineMode());
858
908
  }, ...(ngDevMode ? [{ debugName: "orderedGanttSegments" }] : []));
909
+ canZoomToFit = computed(() => this.orderedGanttSegments().length > 0, ...(ngDevMode ? [{ debugName: "canZoomToFit" }] : []));
910
+ constructor() {
911
+ this.transloco.langChanges$
912
+ .pipe(takeUntilDestroyed(this.destroyRef))
913
+ .subscribe((lang) => this.activeLang.set(lang));
914
+ }
859
915
  // Timeline mode is controlled by parent model signal to keep it externally bindable.
860
916
  onTimelineModeChange(mode) {
861
917
  if (!mode || this.timelineMode() === mode) {
@@ -864,6 +920,12 @@ class Timeline {
864
920
  this.timelineMode.set(mode);
865
921
  this.timelineModeChangeEvent.emit(mode);
866
922
  }
923
+ onZoomToFitToggle() {
924
+ if (!this.canZoomToFit()) {
925
+ return;
926
+ }
927
+ this.zoomToFit.update((current) => !current);
928
+ }
867
929
  // Handles row progress clicks: emits public event and opens details popover.
868
930
  onGanttProgressClick(item, event) {
869
931
  event.stopPropagation();
@@ -920,7 +982,8 @@ class Timeline {
920
982
  }
921
983
  // Recursively maps consumer item shape using accessors from `ganttMapping`.
922
984
  mapNode(source, mapping, state) {
923
- const title = this.resolveString(source, mapping.title) ?? 'Untitled';
985
+ const title = this.resolveString(source, mapping.title) ??
986
+ this.transloco.translate('timeline.untitled');
924
987
  const idRaw = this.resolveAccessor(source, mapping.id);
925
988
  const id = idRaw !== null && idRaw !== undefined && String(idRaw).length
926
989
  ? idRaw
@@ -1136,25 +1199,26 @@ class Timeline {
1136
1199
  return anchor;
1137
1200
  }
1138
1201
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Timeline, deps: [], target: i0.ɵɵFactoryTarget.Component });
1139
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: Timeline, isStandalone: true, selector: "mt-timeline", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, timelineModeOptions: { classPropertyName: "timelineModeOptions", publicName: "timelineModeOptions", isSignal: true, isRequired: false, transformFunction: null }, ganttData: { classPropertyName: "ganttData", publicName: "ganttData", isSignal: true, isRequired: false, transformFunction: null }, ganttMapping: { classPropertyName: "ganttMapping", publicName: "ganttMapping", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, ganttSegmentWidthPx: { classPropertyName: "ganttSegmentWidthPx", publicName: "ganttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, defaultVisibleColumns: { classPropertyName: "defaultVisibleColumns", publicName: "defaultVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMinWidthPx: { classPropertyName: "columnsPaneMinWidthPx", publicName: "columnsPaneMinWidthPx", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMaxWidthPx: { classPropertyName: "columnsPaneMaxWidthPx", publicName: "columnsPaneMaxWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttTitleColumnLabel: { classPropertyName: "ganttTitleColumnLabel", publicName: "ganttTitleColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnLabel: { classPropertyName: "ganttStatusColumnLabel", publicName: "ganttStatusColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttInitiativeColumnWidthPx: { classPropertyName: "ganttInitiativeColumnWidthPx", publicName: "ganttInitiativeColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnWidthPx: { classPropertyName: "ganttStatusColumnWidthPx", publicName: "ganttStatusColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, showGanttStatusColumn: { classPropertyName: "showGanttStatusColumn", publicName: "showGanttStatusColumn", isSignal: true, isRequired: false, transformFunction: null }, showGanttDetailsPopup: { classPropertyName: "showGanttDetailsPopup", publicName: "showGanttDetailsPopup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timelineMode: "timelineModeChange", timelineModeChangeEvent: "timelineModeChangeEvent", ganttItemClick: "ganttItemClick" }, host: { classAttribute: "block" }, queries: [{ propertyName: "ganttTemplate", first: true, predicate: TimelineGanttTemplateDirective, descendants: true, isSignal: true }, { propertyName: "columnTemplates", predicate: (TimelineColumnTemplateDirective), isSignal: true }, { propertyName: "popoverTemplate", first: true, predicate: (TimelinePopoverTemplateDirective), descendants: true, isSignal: true }, { propertyName: "progressTemplate", first: true, predicate: (TimelineProgressTemplateDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "detailsPopover", first: true, predicate: ["detailsPopover"], descendants: true }, { propertyName: "detailsPopoverClickAnchor", first: true, predicate: ["detailsPopoverClickAnchor"], descendants: true }], ngImport: i0, template: "<div class=\"mt-3 block overflow-hidden\">\n <!-- Optional top header (title + timeline mode selector). -->\n @if (showHeader()) {\n <mt-timeline-header\n [title]=\"title()\"\n [timelineMode]=\"timelineMode()\"\n [timelineModeOptions]=\"timelineModeOptions()\"\n (timelineModeChange)=\"onTimelineModeChange($event)\"\n />\n }\n\n <!-- Loading state. -->\n @if (isLoading()) {\n <div class=\"flex min-h-56 items-center justify-center p-8\">\n <div\n class=\"h-8 w-8 animate-spin rounded-full border-2 border-surface-200\"\n style=\"border-top-color: var(--p-primary-color)\"\n ></div>\n </div>\n } @else if (ganttTemplate(); as template) {\n <!-- Full custom gantt-body override. -->\n <div class=\"min-h-56 py-4\">\n <ng-container [ngTemplateOutlet]=\"template.templateRef\"></ng-container>\n </div>\n } @else if (\n mappedGanttNodes().length > 0 && orderedGanttSegments().length > 0\n ) {\n <!-- Built-in gantt renderer. -->\n <mt-timeline-gantt\n [timelineMode]=\"timelineMode()\"\n [columns]=\"columns()\"\n [ganttTitleColumnLabel]=\"ganttTitleColumnLabel()\"\n [ganttStatusColumnLabel]=\"ganttStatusColumnLabel()\"\n [ganttInitiativeColumnWidthPx]=\"ganttInitiativeColumnWidthPx()\"\n [ganttStatusColumnWidthPx]=\"ganttStatusColumnWidthPx()\"\n [showGanttStatusColumn]=\"showGanttStatusColumn()\"\n [ganttSegmentWidthPx]=\"ganttSegmentWidthPx()\"\n [defaultVisibleColumns]=\"defaultVisibleColumns()\"\n [columnsPaneMinWidthPx]=\"columnsPaneMinWidthPx()\"\n [columnsPaneMaxWidthPx]=\"columnsPaneMaxWidthPx()\"\n [mappedGanttNodes]=\"mappedGanttNodes()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [collapsedGanttIds]=\"collapsedGanttIds()\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplate()\"\n (toggleCollapse)=\"toggleGanttCollapse($event)\"\n (progressClick)=\"onGanttProgressClick($event.item, $event.event)\"\n />\n } @else {\n <!-- Empty state. -->\n <div\n class=\"flex min-h-56 items-center justify-center p-8 text-sm text-surface-500\"\n >\n {{ emptyMessage() }}\n </div>\n }\n\n <!-- Details popover host (custom template or built-in fallback). -->\n <p-popover #detailsPopover appendTo=\"body\" (onHide)=\"onDetailsPopoverHide()\">\n @if (showGanttDetailsPopup() && selectedGanttItem(); as item) {\n @if (popoverTemplate(); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template.templateRef\"\n [ngTemplateOutletContext]=\"getPopoverTemplateContext(item)\"\n ></ng-container>\n } @else {\n <mt-timeline-default-popover\n [item]=\"item\"\n (requestClose)=\"hideDetailsPopover()\"\n />\n }\n }\n </p-popover>\n\n <!-- Point anchor used to place the popover exactly where user clicked. -->\n <span\n #detailsPopoverClickAnchor\n class=\"pointer-events-none fixed h-0 w-0\"\n [style.left.px]=\"-9999\"\n [style.top.px]=\"-9999\"\n aria-hidden=\"true\"\n ></span>\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TimelineHeader, selector: "mt-timeline-header", inputs: ["title", "timelineMode", "timelineModeOptions"], outputs: ["timelineModeChange"] }, { kind: "component", type: TimelineGantt, selector: "mt-timeline-gantt", inputs: ["timelineMode", "columns", "ganttTitleColumnLabel", "ganttStatusColumnLabel", "ganttInitiativeColumnWidthPx", "ganttStatusColumnWidthPx", "showGanttStatusColumn", "ganttSegmentWidthPx", "defaultVisibleColumns", "columnsPaneMinWidthPx", "columnsPaneMaxWidthPx", "mappedGanttNodes", "orderedGanttSegments", "collapsedGanttIds", "columnTemplatesByKey", "progressTemplateDirective"], outputs: ["toggleCollapse", "progressClick"] }, { kind: "component", type: TimelineDefaultPopover, selector: "mt-timeline-default-popover", inputs: ["item"], outputs: ["requestClose"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }] });
1202
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: Timeline, isStandalone: true, selector: "mt-timeline", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, showZoomToFitControl: { classPropertyName: "showZoomToFitControl", publicName: "showZoomToFitControl", isSignal: true, isRequired: false, transformFunction: null }, timelineMode: { classPropertyName: "timelineMode", publicName: "timelineMode", isSignal: true, isRequired: false, transformFunction: null }, timelineModeOptions: { classPropertyName: "timelineModeOptions", publicName: "timelineModeOptions", isSignal: true, isRequired: false, transformFunction: null }, zoomToFit: { classPropertyName: "zoomToFit", publicName: "zoomToFit", isSignal: true, isRequired: false, transformFunction: null }, ganttData: { classPropertyName: "ganttData", publicName: "ganttData", isSignal: true, isRequired: false, transformFunction: null }, ganttMapping: { classPropertyName: "ganttMapping", publicName: "ganttMapping", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, ganttSegmentWidthPx: { classPropertyName: "ganttSegmentWidthPx", publicName: "ganttSegmentWidthPx", isSignal: true, isRequired: false, transformFunction: null }, defaultVisibleColumns: { classPropertyName: "defaultVisibleColumns", publicName: "defaultVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMinWidthPx: { classPropertyName: "columnsPaneMinWidthPx", publicName: "columnsPaneMinWidthPx", isSignal: true, isRequired: false, transformFunction: null }, columnsPaneMaxWidthPx: { classPropertyName: "columnsPaneMaxWidthPx", publicName: "columnsPaneMaxWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttTitleColumnLabel: { classPropertyName: "ganttTitleColumnLabel", publicName: "ganttTitleColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnLabel: { classPropertyName: "ganttStatusColumnLabel", publicName: "ganttStatusColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, ganttInitiativeColumnWidthPx: { classPropertyName: "ganttInitiativeColumnWidthPx", publicName: "ganttInitiativeColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, ganttStatusColumnWidthPx: { classPropertyName: "ganttStatusColumnWidthPx", publicName: "ganttStatusColumnWidthPx", isSignal: true, isRequired: false, transformFunction: null }, showGanttStatusColumn: { classPropertyName: "showGanttStatusColumn", publicName: "showGanttStatusColumn", isSignal: true, isRequired: false, transformFunction: null }, showGanttDetailsPopup: { classPropertyName: "showGanttDetailsPopup", publicName: "showGanttDetailsPopup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timelineMode: "timelineModeChange", zoomToFit: "zoomToFitChange", timelineModeChangeEvent: "timelineModeChangeEvent", ganttItemClick: "ganttItemClick" }, host: { classAttribute: "block" }, queries: [{ propertyName: "ganttTemplate", first: true, predicate: TimelineGanttTemplateDirective, descendants: true, isSignal: true }, { propertyName: "columnTemplates", predicate: (TimelineColumnTemplateDirective), isSignal: true }, { propertyName: "popoverTemplate", first: true, predicate: (TimelinePopoverTemplateDirective), descendants: true, isSignal: true }, { propertyName: "progressTemplate", first: true, predicate: (TimelineProgressTemplateDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "detailsPopover", first: true, predicate: ["detailsPopover"], descendants: true }, { propertyName: "detailsPopoverClickAnchor", first: true, predicate: ["detailsPopoverClickAnchor"], descendants: true }], ngImport: i0, template: "<div class=\"mt-3 block overflow-hidden\" *transloco=\"let t; prefix: 'timeline'\">\r\n <!-- Optional top header (title + timeline mode selector). -->\r\n @if (showHeader()) {\r\n <mt-timeline-header\r\n [title]=\"title() || t('timeline')\"\r\n [timelineMode]=\"timelineMode()\"\r\n [timelineModeOptions]=\"resolvedTimelineModeOptions()\"\r\n [showZoomToFitControl]=\"showZoomToFitControl()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [zoomToFitDisabled]=\"!canZoomToFit()\"\r\n (timelineModeChange)=\"onTimelineModeChange($event)\"\r\n (zoomToFitToggle)=\"onZoomToFitToggle()\"\r\n />\r\n }\r\n\r\n <!-- Loading state. -->\r\n @if (isLoading()) {\r\n <div class=\"flex min-h-56 items-center justify-center p-8\">\r\n <div\r\n class=\"h-8 w-8 animate-spin rounded-full border-2 border-surface-200\"\r\n style=\"border-top-color: var(--p-primary-color)\"\r\n ></div>\r\n </div>\r\n } @else if (ganttTemplate(); as template) {\r\n <!-- Full custom gantt-body override. -->\r\n <div class=\"min-h-56 py-4\">\r\n <ng-container [ngTemplateOutlet]=\"template.templateRef\"></ng-container>\r\n </div>\r\n } @else if (\r\n mappedGanttNodes().length > 0 && orderedGanttSegments().length > 0\r\n ) {\r\n <!-- Built-in gantt renderer. -->\r\n <mt-timeline-gantt\r\n [timelineMode]=\"timelineMode()\"\r\n [columns]=\"columns()\"\r\n [ganttTitleColumnLabel]=\"ganttTitleColumnLabel() || t('portfolio-name')\"\r\n [ganttStatusColumnLabel]=\"ganttStatusColumnLabel() || t('status')\"\r\n [ganttInitiativeColumnWidthPx]=\"ganttInitiativeColumnWidthPx()\"\r\n [ganttStatusColumnWidthPx]=\"ganttStatusColumnWidthPx()\"\r\n [showGanttStatusColumn]=\"showGanttStatusColumn()\"\r\n [ganttSegmentWidthPx]=\"ganttSegmentWidthPx()\"\r\n [defaultVisibleColumns]=\"defaultVisibleColumns()\"\r\n [columnsPaneMinWidthPx]=\"columnsPaneMinWidthPx()\"\r\n [columnsPaneMaxWidthPx]=\"columnsPaneMaxWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [mappedGanttNodes]=\"mappedGanttNodes()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [collapsedGanttIds]=\"collapsedGanttIds()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplate()\"\r\n (toggleCollapse)=\"toggleGanttCollapse($event)\"\r\n (progressClick)=\"onGanttProgressClick($event.item, $event.event)\"\r\n />\r\n } @else {\r\n <!-- Empty state. -->\r\n <div\r\n class=\"flex min-h-56 items-center justify-center p-8 text-sm text-surface-500\"\r\n >\r\n {{ emptyMessage() || t(\"empty-message\") }}\r\n </div>\r\n }\r\n\r\n <!-- Details popover host (custom template or built-in fallback). -->\r\n <p-popover #detailsPopover appendTo=\"body\" (onHide)=\"onDetailsPopoverHide()\">\r\n @if (showGanttDetailsPopup() && selectedGanttItem(); as item) {\r\n @if (popoverTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getPopoverTemplateContext(item)\"\r\n ></ng-container>\r\n } @else {\r\n <mt-timeline-default-popover\r\n [item]=\"item\"\r\n (requestClose)=\"hideDetailsPopover()\"\r\n />\r\n }\r\n }\r\n </p-popover>\r\n\r\n <!-- Point anchor used to place the popover exactly where user clicked. -->\r\n <span\r\n #detailsPopoverClickAnchor\r\n class=\"pointer-events-none fixed h-0 w-0\"\r\n [style.left.px]=\"-9999\"\r\n [style.top.px]=\"-9999\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n</div>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: TimelineHeader, selector: "mt-timeline-header", inputs: ["title", "timelineMode", "timelineModeOptions", "showZoomToFitControl", "zoomToFit", "zoomToFitDisabled"], outputs: ["timelineModeChange", "zoomToFitToggle"] }, { kind: "component", type: TimelineGantt, selector: "mt-timeline-gantt", inputs: ["timelineMode", "columns", "ganttTitleColumnLabel", "ganttStatusColumnLabel", "ganttInitiativeColumnWidthPx", "ganttStatusColumnWidthPx", "showGanttStatusColumn", "ganttSegmentWidthPx", "defaultVisibleColumns", "columnsPaneMinWidthPx", "columnsPaneMaxWidthPx", "zoomToFit", "mappedGanttNodes", "orderedGanttSegments", "collapsedGanttIds", "columnTemplatesByKey", "progressTemplateDirective"], outputs: ["toggleCollapse", "progressClick"] }, { kind: "component", type: TimelineDefaultPopover, selector: "mt-timeline-default-popover", inputs: ["item"], outputs: ["requestClose"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1140
1203
  }
1141
1204
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Timeline, decorators: [{
1142
1205
  type: Component,
1143
- args: [{ selector: 'mt-timeline', standalone: true, imports: [
1206
+ args: [{ selector: 'mt-timeline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1144
1207
  CommonModule,
1208
+ TranslocoDirective,
1145
1209
  TimelineHeader,
1146
1210
  TimelineGantt,
1147
1211
  TimelineDefaultPopover,
1148
1212
  Popover,
1149
1213
  NgTemplateOutlet,
1150
- ], host: { class: 'block' }, template: "<div class=\"mt-3 block overflow-hidden\">\n <!-- Optional top header (title + timeline mode selector). -->\n @if (showHeader()) {\n <mt-timeline-header\n [title]=\"title()\"\n [timelineMode]=\"timelineMode()\"\n [timelineModeOptions]=\"timelineModeOptions()\"\n (timelineModeChange)=\"onTimelineModeChange($event)\"\n />\n }\n\n <!-- Loading state. -->\n @if (isLoading()) {\n <div class=\"flex min-h-56 items-center justify-center p-8\">\n <div\n class=\"h-8 w-8 animate-spin rounded-full border-2 border-surface-200\"\n style=\"border-top-color: var(--p-primary-color)\"\n ></div>\n </div>\n } @else if (ganttTemplate(); as template) {\n <!-- Full custom gantt-body override. -->\n <div class=\"min-h-56 py-4\">\n <ng-container [ngTemplateOutlet]=\"template.templateRef\"></ng-container>\n </div>\n } @else if (\n mappedGanttNodes().length > 0 && orderedGanttSegments().length > 0\n ) {\n <!-- Built-in gantt renderer. -->\n <mt-timeline-gantt\n [timelineMode]=\"timelineMode()\"\n [columns]=\"columns()\"\n [ganttTitleColumnLabel]=\"ganttTitleColumnLabel()\"\n [ganttStatusColumnLabel]=\"ganttStatusColumnLabel()\"\n [ganttInitiativeColumnWidthPx]=\"ganttInitiativeColumnWidthPx()\"\n [ganttStatusColumnWidthPx]=\"ganttStatusColumnWidthPx()\"\n [showGanttStatusColumn]=\"showGanttStatusColumn()\"\n [ganttSegmentWidthPx]=\"ganttSegmentWidthPx()\"\n [defaultVisibleColumns]=\"defaultVisibleColumns()\"\n [columnsPaneMinWidthPx]=\"columnsPaneMinWidthPx()\"\n [columnsPaneMaxWidthPx]=\"columnsPaneMaxWidthPx()\"\n [mappedGanttNodes]=\"mappedGanttNodes()\"\n [orderedGanttSegments]=\"orderedGanttSegments()\"\n [collapsedGanttIds]=\"collapsedGanttIds()\"\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\n [progressTemplateDirective]=\"progressTemplate()\"\n (toggleCollapse)=\"toggleGanttCollapse($event)\"\n (progressClick)=\"onGanttProgressClick($event.item, $event.event)\"\n />\n } @else {\n <!-- Empty state. -->\n <div\n class=\"flex min-h-56 items-center justify-center p-8 text-sm text-surface-500\"\n >\n {{ emptyMessage() }}\n </div>\n }\n\n <!-- Details popover host (custom template or built-in fallback). -->\n <p-popover #detailsPopover appendTo=\"body\" (onHide)=\"onDetailsPopoverHide()\">\n @if (showGanttDetailsPopup() && selectedGanttItem(); as item) {\n @if (popoverTemplate(); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template.templateRef\"\n [ngTemplateOutletContext]=\"getPopoverTemplateContext(item)\"\n ></ng-container>\n } @else {\n <mt-timeline-default-popover\n [item]=\"item\"\n (requestClose)=\"hideDetailsPopover()\"\n />\n }\n }\n </p-popover>\n\n <!-- Point anchor used to place the popover exactly where user clicked. -->\n <span\n #detailsPopoverClickAnchor\n class=\"pointer-events-none fixed h-0 w-0\"\n [style.left.px]=\"-9999\"\n [style.top.px]=\"-9999\"\n aria-hidden=\"true\"\n ></span>\n</div>\n", styles: [":host{display:block}\n"] }]
1151
- }], propDecorators: { detailsPopover: [{
1214
+ ], host: { class: 'block' }, template: "<div class=\"mt-3 block overflow-hidden\" *transloco=\"let t; prefix: 'timeline'\">\r\n <!-- Optional top header (title + timeline mode selector). -->\r\n @if (showHeader()) {\r\n <mt-timeline-header\r\n [title]=\"title() || t('timeline')\"\r\n [timelineMode]=\"timelineMode()\"\r\n [timelineModeOptions]=\"resolvedTimelineModeOptions()\"\r\n [showZoomToFitControl]=\"showZoomToFitControl()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [zoomToFitDisabled]=\"!canZoomToFit()\"\r\n (timelineModeChange)=\"onTimelineModeChange($event)\"\r\n (zoomToFitToggle)=\"onZoomToFitToggle()\"\r\n />\r\n }\r\n\r\n <!-- Loading state. -->\r\n @if (isLoading()) {\r\n <div class=\"flex min-h-56 items-center justify-center p-8\">\r\n <div\r\n class=\"h-8 w-8 animate-spin rounded-full border-2 border-surface-200\"\r\n style=\"border-top-color: var(--p-primary-color)\"\r\n ></div>\r\n </div>\r\n } @else if (ganttTemplate(); as template) {\r\n <!-- Full custom gantt-body override. -->\r\n <div class=\"min-h-56 py-4\">\r\n <ng-container [ngTemplateOutlet]=\"template.templateRef\"></ng-container>\r\n </div>\r\n } @else if (\r\n mappedGanttNodes().length > 0 && orderedGanttSegments().length > 0\r\n ) {\r\n <!-- Built-in gantt renderer. -->\r\n <mt-timeline-gantt\r\n [timelineMode]=\"timelineMode()\"\r\n [columns]=\"columns()\"\r\n [ganttTitleColumnLabel]=\"ganttTitleColumnLabel() || t('portfolio-name')\"\r\n [ganttStatusColumnLabel]=\"ganttStatusColumnLabel() || t('status')\"\r\n [ganttInitiativeColumnWidthPx]=\"ganttInitiativeColumnWidthPx()\"\r\n [ganttStatusColumnWidthPx]=\"ganttStatusColumnWidthPx()\"\r\n [showGanttStatusColumn]=\"showGanttStatusColumn()\"\r\n [ganttSegmentWidthPx]=\"ganttSegmentWidthPx()\"\r\n [defaultVisibleColumns]=\"defaultVisibleColumns()\"\r\n [columnsPaneMinWidthPx]=\"columnsPaneMinWidthPx()\"\r\n [columnsPaneMaxWidthPx]=\"columnsPaneMaxWidthPx()\"\r\n [zoomToFit]=\"zoomToFit()\"\r\n [mappedGanttNodes]=\"mappedGanttNodes()\"\r\n [orderedGanttSegments]=\"orderedGanttSegments()\"\r\n [collapsedGanttIds]=\"collapsedGanttIds()\"\r\n [columnTemplatesByKey]=\"columnTemplatesByKey()\"\r\n [progressTemplateDirective]=\"progressTemplate()\"\r\n (toggleCollapse)=\"toggleGanttCollapse($event)\"\r\n (progressClick)=\"onGanttProgressClick($event.item, $event.event)\"\r\n />\r\n } @else {\r\n <!-- Empty state. -->\r\n <div\r\n class=\"flex min-h-56 items-center justify-center p-8 text-sm text-surface-500\"\r\n >\r\n {{ emptyMessage() || t(\"empty-message\") }}\r\n </div>\r\n }\r\n\r\n <!-- Details popover host (custom template or built-in fallback). -->\r\n <p-popover #detailsPopover appendTo=\"body\" (onHide)=\"onDetailsPopoverHide()\">\r\n @if (showGanttDetailsPopup() && selectedGanttItem(); as item) {\r\n @if (popoverTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template.templateRef\"\r\n [ngTemplateOutletContext]=\"getPopoverTemplateContext(item)\"\r\n ></ng-container>\r\n } @else {\r\n <mt-timeline-default-popover\r\n [item]=\"item\"\r\n (requestClose)=\"hideDetailsPopover()\"\r\n />\r\n }\r\n }\r\n </p-popover>\r\n\r\n <!-- Point anchor used to place the popover exactly where user clicked. -->\r\n <span\r\n #detailsPopoverClickAnchor\r\n class=\"pointer-events-none fixed h-0 w-0\"\r\n [style.left.px]=\"-9999\"\r\n [style.top.px]=\"-9999\"\r\n aria-hidden=\"true\"\r\n ></span>\r\n</div>\r\n", styles: [":host{display:block}\n"] }]
1215
+ }], ctorParameters: () => [], propDecorators: { detailsPopover: [{
1152
1216
  type: ViewChild,
1153
1217
  args: ['detailsPopover']
1154
1218
  }], detailsPopoverClickAnchor: [{
1155
1219
  type: ViewChild,
1156
1220
  args: ['detailsPopoverClickAnchor']
1157
- }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }, { type: i0.Output, args: ["timelineModeChange"] }], timelineModeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineModeOptions", required: false }] }], ganttData: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttData", required: false }] }], ganttMapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttMapping", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], ganttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttSegmentWidthPx", required: false }] }], defaultVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultVisibleColumns", required: false }] }], columnsPaneMinWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMinWidthPx", required: false }] }], columnsPaneMaxWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMaxWidthPx", required: false }] }], ganttTitleColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttTitleColumnLabel", required: false }] }], ganttStatusColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnLabel", required: false }] }], ganttInitiativeColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttInitiativeColumnWidthPx", required: false }] }], ganttStatusColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnWidthPx", required: false }] }], showGanttStatusColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttStatusColumn", required: false }] }], showGanttDetailsPopup: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttDetailsPopup", required: false }] }], timelineModeChangeEvent: [{ type: i0.Output, args: ["timelineModeChangeEvent"] }], ganttItemClick: [{ type: i0.Output, args: ["ganttItemClick"] }], ganttTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelineGanttTemplateDirective), { isSignal: true }] }], columnTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TimelineColumnTemplateDirective), { isSignal: true }] }], popoverTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelinePopoverTemplateDirective), { isSignal: true }] }], progressTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelineProgressTemplateDirective), { isSignal: true }] }] } });
1221
+ }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], showZoomToFitControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "showZoomToFitControl", required: false }] }], timelineMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineMode", required: false }] }, { type: i0.Output, args: ["timelineModeChange"] }], timelineModeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timelineModeOptions", required: false }] }], zoomToFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomToFit", required: false }] }, { type: i0.Output, args: ["zoomToFitChange"] }], ganttData: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttData", required: false }] }], ganttMapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttMapping", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], ganttSegmentWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttSegmentWidthPx", required: false }] }], defaultVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultVisibleColumns", required: false }] }], columnsPaneMinWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMinWidthPx", required: false }] }], columnsPaneMaxWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsPaneMaxWidthPx", required: false }] }], ganttTitleColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttTitleColumnLabel", required: false }] }], ganttStatusColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnLabel", required: false }] }], ganttInitiativeColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttInitiativeColumnWidthPx", required: false }] }], ganttStatusColumnWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "ganttStatusColumnWidthPx", required: false }] }], showGanttStatusColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttStatusColumn", required: false }] }], showGanttDetailsPopup: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGanttDetailsPopup", required: false }] }], timelineModeChangeEvent: [{ type: i0.Output, args: ["timelineModeChangeEvent"] }], ganttItemClick: [{ type: i0.Output, args: ["ganttItemClick"] }], ganttTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelineGanttTemplateDirective), { isSignal: true }] }], columnTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TimelineColumnTemplateDirective), { isSignal: true }] }], popoverTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelinePopoverTemplateDirective), { isSignal: true }] }], progressTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TimelineProgressTemplateDirective), { isSignal: true }] }] } });
1158
1222
 
1159
1223
  /**
1160
1224
  * Generated bundle index. Do not edit.