@tekus/design-system 5.35.0 → 5.36.0

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.
@@ -31,6 +31,10 @@ const truncateWithEllipsis = (text, maxLength) => text.length > maxLength ? text
31
31
  * tags, a title, a description, and an optional call-to-action button.
32
32
  * - `error`: `tk-fallback-view` with an illustration and error messages.
33
33
  * Also used when the background image fails to load.
34
+ *
35
+ * Both image and error slides expose a transparent zoom control that emits
36
+ * `slideClick` so the host can open a lightbox (the full-resolution image, or
37
+ * the failure detail for error slides). Plain slides without image are not clickable.
34
38
  */
35
39
  class CarouselItemComponent {
36
40
  constructor() {
@@ -42,6 +46,8 @@ class CarouselItemComponent {
42
46
  this.actionClick = output();
43
47
  /** Emits when the background image fails to load. */
44
48
  this.imageError = output();
49
+ /** Emits when the slide image is clicked (default state with an image only). */
50
+ this.slideClick = output();
45
51
  /** Effective presentation state, combining the slide state and image load failures. */
46
52
  this.state = computed(() => this.hasError() || this.slide().state === 'error' ? 'error' : 'default', ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
47
53
  /** Tags normalized to `CarouselSlideTag` and limited to the maximum allowed by the design. */
@@ -53,6 +59,16 @@ class CarouselItemComponent {
53
59
  }, ...(ngDevMode ? [{ debugName: "visibleTags" }] : /* istanbul ignore next */ []));
54
60
  /** Alternative text for the background image, falling back to the title. */
55
61
  this.altText = computed(() => this.slide().imageAlt ?? this.slide().title, ...(ngDevMode ? [{ debugName: "altText" }] : /* istanbul ignore next */ []));
62
+ /**
63
+ * Whether the clickable zoom control is rendered. It is shown for slides with
64
+ * an image (to enlarge it) and for error slides (to open the failure detail).
65
+ * Plain slides without image are not clickable.
66
+ */
67
+ this.showZoom = computed(() => this.state() === 'error' || !!this.slide().imageSrc, ...(ngDevMode ? [{ debugName: "showZoom" }] : /* istanbul ignore next */ []));
68
+ /** Accessible label for the zoom control, adapted to the slide state. */
69
+ this.zoomLabel = computed(() => this.state() === 'error'
70
+ ? `Ver detalle de ${this.slide().title}`
71
+ : `Ampliar ${this.slide().title}`, ...(ngDevMode ? [{ debugName: "zoomLabel" }] : /* istanbul ignore next */ []));
56
72
  /** Title truncated with an ellipsis when it exceeds the maximum length. */
57
73
  this.displayTitle = computed(() => truncateWithEllipsis(this.slide().title, MAX_TITLE_LENGTH), ...(ngDevMode ? [{ debugName: "displayTitle" }] : /* istanbul ignore next */ []));
58
74
  /** Description truncated with an ellipsis when it exceeds the maximum length. */
@@ -70,13 +86,16 @@ class CarouselItemComponent {
70
86
  onActionClick() {
71
87
  this.actionClick.emit();
72
88
  }
89
+ onSlideClick() {
90
+ this.slideClick.emit();
91
+ }
73
92
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CarouselItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
74
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: CarouselItemComponent, isStandalone: true, selector: "tk-carousel-item", inputs: { slide: { classPropertyName: "slide", publicName: "slide", isSignal: true, isRequired: true, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", imageError: "imageError" }, ngImport: i0, template: "<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:100%}.carousel-item{position:relative;display:flex;flex-direction:column;justify-content:flex-end;width:100%;height:var(--tk-carousel-height, 28.125rem);padding:var(--tk-spacing-padding-xl, 1.5rem);overflow:hidden;box-sizing:border-box}.carousel-item__image{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.carousel-item__overlay{position:absolute;right:0;bottom:0;left:0;height:50%;background:linear-gradient(180deg,#191a1b00,#191a1ba3)}.carousel-item__content{position:relative;display:flex;flex-direction:column;align-items:flex-start;width:100%}.carousel-item__tags{display:flex;gap:var(--tk-spacing-gap-xs, .25rem)}.carousel-item__text{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs, .25rem);width:100%}.carousel-item__title{max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-headers-l, 2rem);font-weight:var(--tk-font-weight-600, 600);line-height:normal;white-space:nowrap;text-overflow:ellipsis}.carousel-item__description{display:-webkit-box;max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-paragraph-m, 1rem);font-weight:var(--tk-font-weight-400, 400);line-height:normal;overflow-wrap:break-word;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.carousel-item__action{width:100%;margin-top:var(--tk-spacing-gap-s, .5rem)}.carousel-item__status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-s, .5rem);width:100%;text-align:center}.carousel-item--plain{background:var(--tk-color-background-inverse, #191a1b)}.carousel-item--error{align-items:center;justify-content:center;background:var(--tk-color-feedback-danger-muted, #ffddd4)}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "iconPosition", "tooltipText", "full", "ariaLabel", "size"], outputs: ["clicked"] }, { kind: "component", type: FallbackViewComponent, selector: "tk-fallback-view", inputs: ["type", "imageSrc", "illustrationAlt", "title", "message", "buttonLabel", "linkLabel", "buttonDisabled"], outputs: ["buttonAction", "linkAction"] }, { kind: "component", type: TagComponent, selector: "tk-tag", inputs: ["value", "severity", "truncationLimit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
93
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: CarouselItemComponent, isStandalone: true, selector: "tk-carousel-item", inputs: { slide: { classPropertyName: "slide", publicName: "slide", isSignal: true, isRequired: true, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", imageError: "imageError", slideClick: "slideClick" }, ngImport: i0, template: "<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @if (showZoom()) {\n <button\n type=\"button\"\n class=\"carousel-item__zoom\"\n [attr.aria-label]=\"zoomLabel()\"\n (click)=\"onSlideClick()\">\n </button>\n }\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:100%}.carousel-item{position:relative;display:flex;flex-direction:column;justify-content:flex-end;width:100%;height:var(--tk-carousel-height, 28.125rem);padding:var(--tk-spacing-padding-xl, 1.5rem);overflow:hidden;box-sizing:border-box}.carousel-item__image{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.carousel-item__overlay{position:absolute;right:0;bottom:0;left:0;height:50%;background:linear-gradient(180deg,#191a1b00,#191a1ba3)}.carousel-item__zoom{position:absolute;inset:0;z-index:1;width:100%;height:100%;padding:0;border:none;background:transparent;cursor:pointer}.carousel-item__zoom:focus-visible{outline:2px solid var(--tk-color-border-focus, #16006f);outline-offset:-2px}.carousel-item__content{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-start;width:100%}.carousel-item__tags{display:flex;gap:var(--tk-spacing-gap-xs, .25rem)}.carousel-item__text{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs, .25rem);width:100%}.carousel-item__title{max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-headers-l, 2rem);font-weight:var(--tk-font-weight-600, 600);line-height:normal;white-space:nowrap;text-overflow:ellipsis}.carousel-item__description{display:-webkit-box;max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-paragraph-m, 1rem);font-weight:var(--tk-font-weight-400, 400);line-height:normal;overflow-wrap:break-word;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.carousel-item__action{width:100%;margin-top:var(--tk-spacing-gap-s, .5rem)}.carousel-item__status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-s, .5rem);width:100%;text-align:center}.carousel-item--plain{background:var(--tk-color-background-inverse, #191a1b)}.carousel-item--error{align-items:center;justify-content:center;background:var(--tk-color-feedback-danger-muted, #ffddd4)}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "iconPosition", "tooltipText", "full", "ariaLabel", "size"], outputs: ["clicked"] }, { kind: "component", type: FallbackViewComponent, selector: "tk-fallback-view", inputs: ["type", "imageSrc", "illustrationAlt", "title", "message", "buttonLabel", "linkLabel", "buttonDisabled"], outputs: ["buttonAction", "linkAction"] }, { kind: "component", type: TagComponent, selector: "tk-tag", inputs: ["value", "severity", "truncationLimit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75
94
  }
76
95
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CarouselItemComponent, decorators: [{
77
96
  type: Component,
78
- args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-carousel-item', imports: [ButtonComponent, FallbackViewComponent, TagComponent], template: "<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:100%}.carousel-item{position:relative;display:flex;flex-direction:column;justify-content:flex-end;width:100%;height:var(--tk-carousel-height, 28.125rem);padding:var(--tk-spacing-padding-xl, 1.5rem);overflow:hidden;box-sizing:border-box}.carousel-item__image{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.carousel-item__overlay{position:absolute;right:0;bottom:0;left:0;height:50%;background:linear-gradient(180deg,#191a1b00,#191a1ba3)}.carousel-item__content{position:relative;display:flex;flex-direction:column;align-items:flex-start;width:100%}.carousel-item__tags{display:flex;gap:var(--tk-spacing-gap-xs, .25rem)}.carousel-item__text{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs, .25rem);width:100%}.carousel-item__title{max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-headers-l, 2rem);font-weight:var(--tk-font-weight-600, 600);line-height:normal;white-space:nowrap;text-overflow:ellipsis}.carousel-item__description{display:-webkit-box;max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-paragraph-m, 1rem);font-weight:var(--tk-font-weight-400, 400);line-height:normal;overflow-wrap:break-word;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.carousel-item__action{width:100%;margin-top:var(--tk-spacing-gap-s, .5rem)}.carousel-item__status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-s, .5rem);width:100%;text-align:center}.carousel-item--plain{background:var(--tk-color-background-inverse, #191a1b)}.carousel-item--error{align-items:center;justify-content:center;background:var(--tk-color-feedback-danger-muted, #ffddd4)}\n"] }]
79
- }], propDecorators: { slide: [{ type: i0.Input, args: [{ isSignal: true, alias: "slide", required: true }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], imageError: [{ type: i0.Output, args: ["imageError"] }] } });
97
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-carousel-item', imports: [ButtonComponent, FallbackViewComponent, TagComponent], template: "<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @if (showZoom()) {\n <button\n type=\"button\"\n class=\"carousel-item__zoom\"\n [attr.aria-label]=\"zoomLabel()\"\n (click)=\"onSlideClick()\">\n </button>\n }\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n", styles: [":host{display:block;height:100%}.carousel-item{position:relative;display:flex;flex-direction:column;justify-content:flex-end;width:100%;height:var(--tk-carousel-height, 28.125rem);padding:var(--tk-spacing-padding-xl, 1.5rem);overflow:hidden;box-sizing:border-box}.carousel-item__image{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.carousel-item__overlay{position:absolute;right:0;bottom:0;left:0;height:50%;background:linear-gradient(180deg,#191a1b00,#191a1ba3)}.carousel-item__zoom{position:absolute;inset:0;z-index:1;width:100%;height:100%;padding:0;border:none;background:transparent;cursor:pointer}.carousel-item__zoom:focus-visible{outline:2px solid var(--tk-color-border-focus, #16006f);outline-offset:-2px}.carousel-item__content{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-start;width:100%}.carousel-item__tags{display:flex;gap:var(--tk-spacing-gap-xs, .25rem)}.carousel-item__text{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs, .25rem);width:100%}.carousel-item__title{max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-headers-l, 2rem);font-weight:var(--tk-font-weight-600, 600);line-height:normal;white-space:nowrap;text-overflow:ellipsis}.carousel-item__description{display:-webkit-box;max-width:100%;margin:0;overflow:hidden;color:var(--tk-color-text-inverse, #ffffff);font-size:var(--tk-font-size-paragraph-m, 1rem);font-weight:var(--tk-font-weight-400, 400);line-height:normal;overflow-wrap:break-word;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}.carousel-item__action{width:100%;margin-top:var(--tk-spacing-gap-s, .5rem)}.carousel-item__status{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-s, .5rem);width:100%;text-align:center}.carousel-item--plain{background:var(--tk-color-background-inverse, #191a1b)}.carousel-item--error{align-items:center;justify-content:center;background:var(--tk-color-feedback-danger-muted, #ffddd4)}\n"] }]
98
+ }], propDecorators: { slide: [{ type: i0.Input, args: [{ isSignal: true, alias: "slide", required: true }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], imageError: [{ type: i0.Output, args: ["imageError"] }], slideClick: [{ type: i0.Output, args: ["slideClick"] }] } });
80
99
 
81
100
  /**
82
101
  * @component CarouselComponent
@@ -109,7 +128,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
109
128
  * <tk-carousel
110
129
  * [slides]="slides"
111
130
  * (slideChange)="onSlideChange($event)"
112
- * (actionClick)="onActionClick($event)">
131
+ * (actionClick)="onActionClick($event)"
132
+ * (slideClick)="openLightbox($event)">
113
133
  * </tk-carousel>
114
134
  * ```
115
135
  *
@@ -140,6 +160,8 @@ class CarouselComponent {
140
160
  this.slideChange = output();
141
161
  /** Emits the slide whose call-to-action button was clicked. */
142
162
  this.actionClick = output();
163
+ /** Emits the slide whose image was clicked, so consumers can open a lightbox. */
164
+ this.slideClick = output();
143
165
  /** Reference to the underlying PrimeNG carousel, used for thumbnail navigation. */
144
166
  this.primeCarousel = viewChild(Carousel, ...(ngDevMode ? [{ debugName: "primeCarousel" }] : /* istanbul ignore next */ []));
145
167
  /** Zero-based index of the active slide within the visible slides. */
@@ -190,16 +212,19 @@ class CarouselComponent {
190
212
  onActionClick(slide) {
191
213
  this.actionClick.emit(slide);
192
214
  }
215
+ onSlideClick(slide) {
216
+ this.slideClick.emit(slide);
217
+ }
193
218
  hasSlideError(slide) {
194
219
  return slide.state === 'error' || this.failedSlideIds().has(slide.id);
195
220
  }
196
221
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
197
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: CarouselComponent, isStandalone: true, selector: "tk-carousel", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, indicator: { classPropertyName: "indicator", publicName: "indicator", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { slideChange: "slideChange", actionClick: "actionClick" }, viewQueries: [{ propertyName: "primeCarousel", first: true, predicate: Carousel, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.carousel{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-s, .5rem);width:100%}.carousel__thumbnails{display:flex;gap:var(--tk-spacing-gap-xs, .25rem);width:100%;overflow-x:auto}.carousel__thumbnail{flex-shrink:0;width:3.75rem;height:2.5rem;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;overflow:hidden;cursor:pointer}.carousel__thumbnail--active{outline:2px solid var(--tk-color-primary-default, #16006f);outline-offset:-2px}.carousel__thumbnail:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:-2px}.carousel__thumbnail-image{display:block;width:100%;height:100%;object-fit:cover;border-radius:var(--tk-borderRadius-xs, .25rem)}.carousel__thumbnail-placeholder{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:var(--tk-borderRadius-xs, .25rem);background:var(--tk-color-background-medium, #d2d2d2)}.carousel__thumbnail-placeholder--error{background:var(--tk-color-feedback-danger-muted, #ffddd4);color:var(--tk-color-feedback-danger-default, #dc362e)}:host ::ng-deep .carousel .p-carousel{width:100%}:host ::ng-deep .carousel .p-carousel-content-container{position:relative;border-radius:var(--tk-borderRadius-m, 1rem) var(--tk-borderRadius-m, 1rem) 0 0;overflow:hidden}:host ::ng-deep .carousel .p-carousel-content{position:relative;gap:0}:host ::ng-deep .carousel .p-carousel-viewport{width:100%}:host ::ng-deep .carousel .p-carousel-prev-button,:host ::ng-deep .carousel .p-carousel-next-button{position:absolute;top:50%;z-index:1;width:2.5rem;height:2.5rem;transform:translateY(-50%);border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:#f2f1f166;color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button tk-icon,:host ::ng-deep .carousel .p-carousel-prev-button svg,:host ::ng-deep .carousel .p-carousel-next-button tk-icon,:host ::ng-deep .carousel .p-carousel-next-button svg{color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button .p-button,:host ::ng-deep .carousel .p-carousel-next-button .p-button{width:100%;height:100%;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;color:inherit;box-shadow:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):active,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):active{border:none;background:transparent;color:inherit}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{border:none;box-shadow:none;outline:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-prev-button:hover,:host ::ng-deep .carousel .p-carousel-next-button:hover{background:#f2f1f199}:host ::ng-deep .carousel .p-carousel-prev-button.p-disabled,:host ::ng-deep .carousel .p-carousel-next-button.p-disabled{opacity:.4}:host ::ng-deep .carousel .p-carousel-prev-button{left:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-next-button{right:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-indicator-list{position:absolute;right:0;bottom:var(--tk-spacing-padding-s, .5rem);left:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-xs, .25rem);margin:0;padding:0}:host ::ng-deep .carousel .p-carousel-indicator-button{width:.5rem;height:.5rem;border-radius:var(--tk-borderRadius-full, 62.4375rem);background:var(--tk-color-background-medium, #d2d2d2);transition:width .2s ease,background .2s ease}:host ::ng-deep .carousel .p-carousel-indicator-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-indicator-active .p-carousel-indicator-button{width:1rem;background:var(--tk-color-background-strong, #8a8a8b)}\n"], dependencies: [{ kind: "ngmodule", type: CarouselModule }, { kind: "component", type: i1.Carousel, selector: "p-carousel", inputs: ["page", "numVisible", "numScroll", "responsiveOptions", "orientation", "verticalViewPortHeight", "contentClass", "indicatorsContentClass", "indicatorsContentStyle", "indicatorStyleClass", "indicatorStyle", "value", "circular", "showIndicators", "showNavigators", "autoplayInterval", "styleClass", "prevButtonProps", "nextButtonProps"], outputs: ["onPage"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: CarouselItemComponent, selector: "tk-carousel-item", inputs: ["slide", "hasError"], outputs: ["actionClick", "imageError"] }, { kind: "component", type: IconComponent, selector: "tk-icon", inputs: ["icon", "styleIcon", "color", "size", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
222
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: CarouselComponent, isStandalone: true, selector: "tk-carousel", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, indicator: { classPropertyName: "indicator", publicName: "indicator", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { slideChange: "slideChange", actionClick: "actionClick", slideClick: "slideClick" }, viewQueries: [{ propertyName: "primeCarousel", first: true, predicate: Carousel, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\"\n (slideClick)=\"onSlideClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.carousel{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-s, .5rem);width:100%}.carousel__thumbnails{display:flex;gap:var(--tk-spacing-gap-xs, .25rem);width:100%;overflow-x:auto}.carousel__thumbnail{flex-shrink:0;width:3.75rem;height:2.5rem;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;overflow:hidden;cursor:pointer}.carousel__thumbnail--active{outline:2px solid var(--tk-color-primary-default, #16006f);outline-offset:-2px}.carousel__thumbnail:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:-2px}.carousel__thumbnail-image{display:block;width:100%;height:100%;object-fit:cover;border-radius:var(--tk-borderRadius-xs, .25rem)}.carousel__thumbnail-placeholder{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:var(--tk-borderRadius-xs, .25rem);background:var(--tk-color-background-medium, #d2d2d2)}.carousel__thumbnail-placeholder--error{background:var(--tk-color-feedback-danger-muted, #ffddd4);color:var(--tk-color-feedback-danger-default, #dc362e)}:host ::ng-deep .carousel .p-carousel{width:100%}:host ::ng-deep .carousel .p-carousel-content-container{position:relative;border-radius:var(--tk-borderRadius-m, 1rem) var(--tk-borderRadius-m, 1rem) 0 0;overflow:hidden}:host ::ng-deep .carousel .p-carousel-content{position:relative;gap:0}:host ::ng-deep .carousel .p-carousel-viewport{width:100%}:host ::ng-deep .carousel .p-carousel-prev-button,:host ::ng-deep .carousel .p-carousel-next-button{position:absolute;top:50%;z-index:1;width:2.5rem;height:2.5rem;transform:translateY(-50%);border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:#f2f1f166;color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button tk-icon,:host ::ng-deep .carousel .p-carousel-prev-button svg,:host ::ng-deep .carousel .p-carousel-next-button tk-icon,:host ::ng-deep .carousel .p-carousel-next-button svg{color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button .p-button,:host ::ng-deep .carousel .p-carousel-next-button .p-button{width:100%;height:100%;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;color:inherit;box-shadow:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):active,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):active{border:none;background:transparent;color:inherit}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{border:none;box-shadow:none;outline:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-prev-button:hover,:host ::ng-deep .carousel .p-carousel-next-button:hover{background:#f2f1f199}:host ::ng-deep .carousel .p-carousel-prev-button.p-disabled,:host ::ng-deep .carousel .p-carousel-next-button.p-disabled{opacity:.4}:host ::ng-deep .carousel .p-carousel-prev-button{left:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-next-button{right:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-indicator-list{position:absolute;right:0;bottom:var(--tk-spacing-padding-s, .5rem);left:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-xs, .25rem);margin:0;padding:0}:host ::ng-deep .carousel .p-carousel-indicator-button{width:.5rem;height:.5rem;border-radius:var(--tk-borderRadius-full, 62.4375rem);background:var(--tk-color-background-medium, #d2d2d2);transition:width .2s ease,background .2s ease}:host ::ng-deep .carousel .p-carousel-indicator-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-indicator-active .p-carousel-indicator-button{width:1rem;background:var(--tk-color-background-strong, #8a8a8b)}\n"], dependencies: [{ kind: "ngmodule", type: CarouselModule }, { kind: "component", type: i1.Carousel, selector: "p-carousel", inputs: ["page", "numVisible", "numScroll", "responsiveOptions", "orientation", "verticalViewPortHeight", "contentClass", "indicatorsContentClass", "indicatorsContentStyle", "indicatorStyleClass", "indicatorStyle", "value", "circular", "showIndicators", "showNavigators", "autoplayInterval", "styleClass", "prevButtonProps", "nextButtonProps"], outputs: ["onPage"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: CarouselItemComponent, selector: "tk-carousel-item", inputs: ["slide", "hasError"], outputs: ["actionClick", "imageError", "slideClick"] }, { kind: "component", type: IconComponent, selector: "tk-icon", inputs: ["icon", "styleIcon", "color", "size", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
198
223
  }
199
224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CarouselComponent, decorators: [{
200
225
  type: Component,
201
- args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-carousel', imports: [CarouselModule, CarouselItemComponent, IconComponent], template: "<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.carousel{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-s, .5rem);width:100%}.carousel__thumbnails{display:flex;gap:var(--tk-spacing-gap-xs, .25rem);width:100%;overflow-x:auto}.carousel__thumbnail{flex-shrink:0;width:3.75rem;height:2.5rem;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;overflow:hidden;cursor:pointer}.carousel__thumbnail--active{outline:2px solid var(--tk-color-primary-default, #16006f);outline-offset:-2px}.carousel__thumbnail:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:-2px}.carousel__thumbnail-image{display:block;width:100%;height:100%;object-fit:cover;border-radius:var(--tk-borderRadius-xs, .25rem)}.carousel__thumbnail-placeholder{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:var(--tk-borderRadius-xs, .25rem);background:var(--tk-color-background-medium, #d2d2d2)}.carousel__thumbnail-placeholder--error{background:var(--tk-color-feedback-danger-muted, #ffddd4);color:var(--tk-color-feedback-danger-default, #dc362e)}:host ::ng-deep .carousel .p-carousel{width:100%}:host ::ng-deep .carousel .p-carousel-content-container{position:relative;border-radius:var(--tk-borderRadius-m, 1rem) var(--tk-borderRadius-m, 1rem) 0 0;overflow:hidden}:host ::ng-deep .carousel .p-carousel-content{position:relative;gap:0}:host ::ng-deep .carousel .p-carousel-viewport{width:100%}:host ::ng-deep .carousel .p-carousel-prev-button,:host ::ng-deep .carousel .p-carousel-next-button{position:absolute;top:50%;z-index:1;width:2.5rem;height:2.5rem;transform:translateY(-50%);border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:#f2f1f166;color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button tk-icon,:host ::ng-deep .carousel .p-carousel-prev-button svg,:host ::ng-deep .carousel .p-carousel-next-button tk-icon,:host ::ng-deep .carousel .p-carousel-next-button svg{color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button .p-button,:host ::ng-deep .carousel .p-carousel-next-button .p-button{width:100%;height:100%;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;color:inherit;box-shadow:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):active,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):active{border:none;background:transparent;color:inherit}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{border:none;box-shadow:none;outline:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-prev-button:hover,:host ::ng-deep .carousel .p-carousel-next-button:hover{background:#f2f1f199}:host ::ng-deep .carousel .p-carousel-prev-button.p-disabled,:host ::ng-deep .carousel .p-carousel-next-button.p-disabled{opacity:.4}:host ::ng-deep .carousel .p-carousel-prev-button{left:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-next-button{right:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-indicator-list{position:absolute;right:0;bottom:var(--tk-spacing-padding-s, .5rem);left:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-xs, .25rem);margin:0;padding:0}:host ::ng-deep .carousel .p-carousel-indicator-button{width:.5rem;height:.5rem;border-radius:var(--tk-borderRadius-full, 62.4375rem);background:var(--tk-color-background-medium, #d2d2d2);transition:width .2s ease,background .2s ease}:host ::ng-deep .carousel .p-carousel-indicator-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-indicator-active .p-carousel-indicator-button{width:1rem;background:var(--tk-color-background-strong, #8a8a8b)}\n"] }]
202
- }], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], indicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicator", required: false }] }], slideChange: [{ type: i0.Output, args: ["slideChange"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], primeCarousel: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Carousel), { isSignal: true }] }] } });
226
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-carousel', imports: [CarouselModule, CarouselItemComponent, IconComponent], template: "<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\"\n (slideClick)=\"onSlideClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}.carousel{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-s, .5rem);width:100%}.carousel__thumbnails{display:flex;gap:var(--tk-spacing-gap-xs, .25rem);width:100%;overflow-x:auto}.carousel__thumbnail{flex-shrink:0;width:3.75rem;height:2.5rem;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;overflow:hidden;cursor:pointer}.carousel__thumbnail--active{outline:2px solid var(--tk-color-primary-default, #16006f);outline-offset:-2px}.carousel__thumbnail:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:-2px}.carousel__thumbnail-image{display:block;width:100%;height:100%;object-fit:cover;border-radius:var(--tk-borderRadius-xs, .25rem)}.carousel__thumbnail-placeholder{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:var(--tk-borderRadius-xs, .25rem);background:var(--tk-color-background-medium, #d2d2d2)}.carousel__thumbnail-placeholder--error{background:var(--tk-color-feedback-danger-muted, #ffddd4);color:var(--tk-color-feedback-danger-default, #dc362e)}:host ::ng-deep .carousel .p-carousel{width:100%}:host ::ng-deep .carousel .p-carousel-content-container{position:relative;border-radius:var(--tk-borderRadius-m, 1rem) var(--tk-borderRadius-m, 1rem) 0 0;overflow:hidden}:host ::ng-deep .carousel .p-carousel-content{position:relative;gap:0}:host ::ng-deep .carousel .p-carousel-viewport{width:100%}:host ::ng-deep .carousel .p-carousel-prev-button,:host ::ng-deep .carousel .p-carousel-next-button{position:absolute;top:50%;z-index:1;width:2.5rem;height:2.5rem;transform:translateY(-50%);border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:#f2f1f166;color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button tk-icon,:host ::ng-deep .carousel .p-carousel-prev-button svg,:host ::ng-deep .carousel .p-carousel-next-button tk-icon,:host ::ng-deep .carousel .p-carousel-next-button svg{color:var(--tk-color-text-default, #191a1b)}:host ::ng-deep .carousel .p-carousel-prev-button .p-button,:host ::ng-deep .carousel .p-carousel-next-button .p-button{width:100%;height:100%;padding:0;border:none;border-radius:var(--tk-borderRadius-xs, .25rem);background:transparent;color:inherit;box-shadow:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:not(:disabled):active,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):hover,:host ::ng-deep .carousel .p-carousel-next-button .p-button:not(:disabled):active{border:none;background:transparent;color:inherit}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{border:none;box-shadow:none;outline:none}:host ::ng-deep .carousel .p-carousel-prev-button .p-button:focus-visible,:host ::ng-deep .carousel .p-carousel-next-button .p-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-prev-button:hover,:host ::ng-deep .carousel .p-carousel-next-button:hover{background:#f2f1f199}:host ::ng-deep .carousel .p-carousel-prev-button.p-disabled,:host ::ng-deep .carousel .p-carousel-next-button.p-disabled{opacity:.4}:host ::ng-deep .carousel .p-carousel-prev-button{left:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-next-button{right:var(--tk-spacing-padding-m, 1rem)}:host ::ng-deep .carousel .p-carousel-indicator-list{position:absolute;right:0;bottom:var(--tk-spacing-padding-s, .5rem);left:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:var(--tk-spacing-gap-xs, .25rem);margin:0;padding:0}:host ::ng-deep .carousel .p-carousel-indicator-button{width:.5rem;height:.5rem;border-radius:var(--tk-borderRadius-full, 62.4375rem);background:var(--tk-color-background-medium, #d2d2d2);transition:width .2s ease,background .2s ease}:host ::ng-deep .carousel .p-carousel-indicator-button:focus-visible{outline:2px solid var(--tk-color-border-focus, #6ad0bc);outline-offset:2px}:host ::ng-deep .carousel .p-carousel-indicator-active .p-carousel-indicator-button{width:1rem;background:var(--tk-color-background-strong, #8a8a8b)}\n"] }]
227
+ }], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], indicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicator", required: false }] }], slideChange: [{ type: i0.Output, args: ["slideChange"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], slideClick: [{ type: i0.Output, args: ["slideClick"] }], primeCarousel: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Carousel), { isSignal: true }] }] } });
203
228
 
204
229
  /**
205
230
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"tekus-design-system-components-carousel.mjs","sources":["../../../projects/design-system/components/carousel/src/carousel.types.ts","../../../projects/design-system/components/carousel/src/carousel-item.component.ts","../../../projects/design-system/components/carousel/src/carousel-item.component.html","../../../projects/design-system/components/carousel/src/carousel.component.ts","../../../projects/design-system/components/carousel/src/carousel.component.html","../../../projects/design-system/components/carousel/tekus-design-system-components-carousel.ts"],"sourcesContent":["import { TagSeverity } from '@tekus/design-system/components/tag';\n\n/**\n * Behavioral preset of the carousel. The rotation is always an infinite\n * loop: after the last slide, next returns to the first one.\n * - `'manual'`: the user navigates with arrows and indicator; failed slide\n * images show an error fallback in place.\n * - `'autoplay'`: the rotation advances automatically every 7 seconds with\n * swipe gestures enabled; failed slide images remove the slide from the\n * rotation without any error message (unattended usage).\n */\nexport type CarouselVariant = 'manual' | 'autoplay';\n\n/**\n * Type of position indicator rendered by the carousel.\n * - `'dots'`: dot indicators overlaid at the bottom of the slide.\n * - `'thumbnails'`: clickable image thumbnails rendered below the slide.\n */\nexport type CarouselIndicatorType = 'dots' | 'thumbnails';\n\n/**\n * Presentation state of a slide.\n * - `'default'`: regular slide with image and content.\n * - `'error'`: error view rendered with `tk-fallback-view`.\n *\n * Independently of this consumer-driven state, a slide whose image fails to\n * load is switched to the error view automatically.\n */\nexport type CarouselSlideState = 'default' | 'error';\n\n/**\n * Tag displayed over a slide, with an optional color scheme.\n * The severity accepts the same values as `tk-tag`\n * (`'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger' | 'contrast'`).\n */\nexport interface CarouselSlideTag {\n /** Text of the tag. */\n value: string;\n /**\n * Color scheme of the tag, forwarded to `tk-tag`.\n * @default 'primary'\n */\n severity?: TagSeverity;\n}\n\n/**\n * Data contract for a single carousel slide.\n */\nexport interface CarouselSlide {\n /** Stable unique identifier, used for tracking and error handling. */\n id: string | number;\n /** URL of the slide background image. When omitted, the content is rendered over a dark background. */\n imageSrc?: string;\n /** Alternative text for the background image. Falls back to `title`. */\n imageAlt?: string;\n /** Main heading displayed over the image. */\n title: string;\n /** Supporting text displayed below the title. */\n description?: string;\n /**\n * Short labels displayed above the title. Only the first two are rendered.\n * Plain strings render with the default color scheme; use `CarouselSlideTag`\n * objects to set a severity per tag.\n */\n tags?: (string | CarouselSlideTag)[];\n /** Label of the call-to-action button. When omitted, no button is rendered. */\n actionLabel?: string;\n /** Icon name (from the design system IconCatalog) shown in the action button. */\n actionIcon?: string;\n /**\n * Consumer-driven presentation state of the slide.\n * @default 'default'\n */\n state?: CarouselSlideState;\n /** Illustration URL for the error view, forwarded to `tk-fallback-view`. */\n errorImageSrc?: string;\n /** Title of the error view (manual variant only). */\n errorTitle?: string;\n /** Message of the error view (manual variant only). */\n errorDescription?: string;\n}\n\n/**\n * Payload emitted when the active slide changes.\n */\nexport interface CarouselSlideChangeEvent {\n /** Zero-based index of the active slide within the visible slides. */\n index: number;\n /** The slide that became active. */\n slide: CarouselSlide;\n}\n\n/** Autoplay interval, in milliseconds, applied by the autoplay variant. */\nexport const AUTOPLAY_INTERVAL_MS = 7000;\n\n/** Maximum number of tags rendered per slide. */\nexport const MAX_VISIBLE_TAGS = 2;\n\n/** Maximum number of characters of the slide title before truncation. */\nexport const MAX_TITLE_LENGTH = 50;\n\n/** Maximum number of characters of the slide description before truncation. */\nexport const MAX_DESCRIPTION_LENGTH = 140;\n\n/** Maximum number of characters per tag before truncation. */\nexport const MAX_TAG_LENGTH = 20;\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\n\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { FallbackViewComponent } from '@tekus/design-system/components/fallback-view';\nimport { TagComponent } from '@tekus/design-system/components/tag';\n\nimport {\n CarouselSlide,\n CarouselSlideState,\n CarouselSlideTag,\n MAX_DESCRIPTION_LENGTH,\n MAX_TAG_LENGTH,\n MAX_TITLE_LENGTH,\n MAX_VISIBLE_TAGS,\n} from './carousel.types';\n\nconst truncateWithEllipsis = (text: string, maxLength: number): string =>\n text.length > maxLength ? text.substring(0, maxLength) + '…' : text;\n\n/**\n * @component CarouselItemComponent\n * @description\n * Internal slide renderer for `tk-carousel`. It is not part of the public API\n * of the design system and must only be used by `CarouselComponent`.\n *\n * Renders one of two views depending on the slide state:\n * - `default`: background image with a bottom gradient overlay, up to two\n * tags, a title, a description, and an optional call-to-action button.\n * - `error`: `tk-fallback-view` with an illustration and error messages.\n * Also used when the background image fails to load.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-carousel-item',\n imports: [ButtonComponent, FallbackViewComponent, TagComponent],\n templateUrl: './carousel-item.component.html',\n styleUrl: './carousel-item.component.scss',\n})\nexport class CarouselItemComponent {\n /** Slide data to render. */\n slide = input.required<CarouselSlide>();\n\n /** Whether the slide image failed to load and the error view must be shown. */\n hasError = input<boolean>(false);\n\n /** Emits when the call-to-action button is clicked. */\n actionClick = output<void>();\n\n /** Emits when the background image fails to load. */\n imageError = output<void>();\n\n /** Effective presentation state, combining the slide state and image load failures. */\n state = computed<CarouselSlideState>(() =>\n this.hasError() || this.slide().state === 'error' ? 'error' : 'default'\n );\n\n /** Tags normalized to `CarouselSlideTag` and limited to the maximum allowed by the design. */\n visibleTags = computed<CarouselSlideTag[]>(() => {\n const tags = this.slide().tags ?? [];\n return tags\n .slice(0, MAX_VISIBLE_TAGS)\n .map((tag) => (typeof tag === 'string' ? { value: tag } : tag));\n });\n\n /** Alternative text for the background image, falling back to the title. */\n altText = computed(() => this.slide().imageAlt ?? this.slide().title);\n\n /** Title truncated with an ellipsis when it exceeds the maximum length. */\n displayTitle = computed(() =>\n truncateWithEllipsis(this.slide().title, MAX_TITLE_LENGTH)\n );\n\n /** Description truncated with an ellipsis when it exceeds the maximum length. */\n displayDescription = computed(() =>\n truncateWithEllipsis(this.slide().description ?? '', MAX_DESCRIPTION_LENGTH)\n );\n\n /** Error title truncated with an ellipsis, using the same limit as the title. */\n displayErrorTitle = computed(() =>\n truncateWithEllipsis(this.slide().errorTitle ?? '', MAX_TITLE_LENGTH)\n );\n\n /** Error message truncated with an ellipsis, using the same limit as the description. */\n displayErrorDescription = computed(() =>\n truncateWithEllipsis(this.slide().errorDescription ?? '', MAX_DESCRIPTION_LENGTH)\n );\n\n /** Maximum characters per tag, forwarded to `tk-tag`. */\n readonly tagTruncationLimit = MAX_TAG_LENGTH;\n\n onImageError(): void {\n this.imageError.emit();\n }\n\n onActionClick(): void {\n this.actionClick.emit();\n }\n}\n","<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { Carousel, CarouselModule, CarouselPageEvent } from 'primeng/carousel';\nimport { IconComponent } from '@tekus/design-system/components/icon';\n\nimport { CarouselItemComponent } from './carousel-item.component';\nimport {\n AUTOPLAY_INTERVAL_MS,\n CarouselIndicatorType,\n CarouselSlide,\n CarouselSlideChangeEvent,\n CarouselVariant,\n} from './carousel.types';\n\n/**\n * @component CarouselComponent\n * @description\n * Adaptive carousel that displays a sequence of slides one at a time, each\n * with a background image, up to two tags, a title, a description, and an\n * optional call-to-action button. It wraps PrimeNG's `p-carousel` with the\n * Tekus design system look.\n *\n * The rotation is always an infinite loop: after the last slide, next returns\n * to the first one.\n *\n * Variants (`variant` input):\n * - `'manual'` (default): the user navigates with arrows and indicator; if a\n * slide image fails to load, an error fallback is shown in its place.\n * - `'autoplay'`: the rotation advances automatically every 7 seconds with\n * swipe gestures enabled; slides whose image fails to load are removed\n * from the rotation silently (unattended usage).\n *\n * Indicators (`indicator` input):\n * - `'dots'` (default): dot indicators overlaid at the bottom of the slide.\n * - `'thumbnails'`: clickable image thumbnails rendered below the slide.\n *\n * The slide height can be customized with the `--tk-carousel-height` CSS\n * variable (defaults to `28.125rem`).\n *\n * @usage\n * ### Manual navigation (default)\n * ```html\n * <tk-carousel\n * [slides]=\"slides\"\n * (slideChange)=\"onSlideChange($event)\"\n * (actionClick)=\"onActionClick($event)\">\n * </tk-carousel>\n * ```\n *\n * ### Autoplay with thumbnails\n * ```html\n * <tk-carousel\n * [slides]=\"slides\"\n * variant=\"autoplay\"\n * indicator=\"thumbnails\">\n * </tk-carousel>\n * ```\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-carousel',\n imports: [CarouselModule, CarouselItemComponent, IconComponent],\n templateUrl: './carousel.component.html',\n styleUrl: './carousel.component.scss',\n})\nexport class CarouselComponent {\n /** Slides to display. Each slide must have a stable unique `id`. */\n slides = input.required<CarouselSlide[]>();\n\n /**\n * Behavioral preset of the carousel.\n * @default 'manual'\n */\n variant = input<CarouselVariant>('manual');\n\n /**\n * Type of position indicator.\n * @default 'dots'\n */\n indicator = input<CarouselIndicatorType>('dots');\n\n /** Emits when the active slide changes, via arrows, indicator, swipe, or autoplay. */\n slideChange = output<CarouselSlideChangeEvent>();\n\n /** Emits the slide whose call-to-action button was clicked. */\n actionClick = output<CarouselSlide>();\n\n /** Reference to the underlying PrimeNG carousel, used for thumbnail navigation. */\n primeCarousel = viewChild(Carousel);\n\n /** Zero-based index of the active slide within the visible slides. */\n currentIndex = signal(0);\n\n /** Ids of the slides whose image failed to load. */\n failedSlideIds = signal<ReadonlySet<CarouselSlide['id']>>(new Set());\n\n /** Whether the autoplay preset is active. */\n isAutoplay = computed(() => this.variant() === 'autoplay');\n\n /** Autoplay interval mapped from the variant preset. `0` disables autoplay. */\n autoplayInterval = computed(() =>\n this.isAutoplay() ? AUTOPLAY_INTERVAL_MS : 0\n );\n\n /**\n * Slides currently part of the rotation. The autoplay variant excludes\n * slides whose image failed to load; the manual variant keeps them and\n * shows an error fallback instead.\n */\n visibleSlides = computed(() => {\n const failed = this.failedSlideIds();\n const slides = this.slides();\n if (!this.isAutoplay() || failed.size === 0) {\n return slides;\n }\n return slides.filter((slide) => !failed.has(slide.id));\n });\n\n /**\n * Whether the navigation controls (arrows and indicators) are rendered.\n * With a single visible slide there is nowhere to navigate, so they are hidden.\n */\n showNavigation = computed(() => this.visibleSlides().length > 1);\n\n /** Whether the dot indicator is rendered. */\n showDots = computed(() => this.indicator() === 'dots' && this.showNavigation());\n\n /** Whether the thumbnail indicator is rendered. */\n showThumbnails = computed(\n () => this.indicator() === 'thumbnails' && this.showNavigation()\n );\n\n onPage(event: CarouselPageEvent): void {\n const index = event.page ?? 0;\n this.currentIndex.set(index);\n const slide = this.visibleSlides()[index];\n if (slide) {\n this.slideChange.emit({ index, slide });\n }\n }\n\n onThumbnailClick(event: MouseEvent, index: number): void {\n this.primeCarousel()?.onDotClick(event, index);\n }\n\n onImageError(slide: CarouselSlide): void {\n this.failedSlideIds.update((failed) => new Set(failed).add(slide.id));\n }\n\n onActionClick(slide: CarouselSlide): void {\n this.actionClick.emit(slide);\n }\n\n hasSlideError(slide: CarouselSlide): boolean {\n return slide.state === 'error' || this.failedSlideIds().has(slide.id);\n }\n}\n","<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tekus-design-system-components-carousel.mjs","sources":["../../../projects/design-system/components/carousel/src/carousel.types.ts","../../../projects/design-system/components/carousel/src/carousel-item.component.ts","../../../projects/design-system/components/carousel/src/carousel-item.component.html","../../../projects/design-system/components/carousel/src/carousel.component.ts","../../../projects/design-system/components/carousel/src/carousel.component.html","../../../projects/design-system/components/carousel/tekus-design-system-components-carousel.ts"],"sourcesContent":["import { TagSeverity } from '@tekus/design-system/components/tag';\n\n/**\n * Behavioral preset of the carousel. The rotation is always an infinite\n * loop: after the last slide, next returns to the first one.\n * - `'manual'`: the user navigates with arrows and indicator; failed slide\n * images show an error fallback in place.\n * - `'autoplay'`: the rotation advances automatically every 7 seconds with\n * swipe gestures enabled; failed slide images remove the slide from the\n * rotation without any error message (unattended usage).\n */\nexport type CarouselVariant = 'manual' | 'autoplay';\n\n/**\n * Type of position indicator rendered by the carousel.\n * - `'dots'`: dot indicators overlaid at the bottom of the slide.\n * - `'thumbnails'`: clickable image thumbnails rendered below the slide.\n */\nexport type CarouselIndicatorType = 'dots' | 'thumbnails';\n\n/**\n * Presentation state of a slide.\n * - `'default'`: regular slide with image and content.\n * - `'error'`: error view rendered with `tk-fallback-view`.\n *\n * Independently of this consumer-driven state, a slide whose image fails to\n * load is switched to the error view automatically.\n */\nexport type CarouselSlideState = 'default' | 'error';\n\n/**\n * Tag displayed over a slide, with an optional color scheme.\n * The severity accepts the same values as `tk-tag`\n * (`'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger' | 'contrast'`).\n */\nexport interface CarouselSlideTag {\n /** Text of the tag. */\n value: string;\n /**\n * Color scheme of the tag, forwarded to `tk-tag`.\n * @default 'primary'\n */\n severity?: TagSeverity;\n}\n\n/**\n * Data contract for a single carousel slide.\n */\nexport interface CarouselSlide {\n /** Stable unique identifier, used for tracking and error handling. */\n id: string | number;\n /** URL of the slide background image. When omitted, the content is rendered over a dark background. */\n imageSrc?: string;\n /** Alternative text for the background image. Falls back to `title`. */\n imageAlt?: string;\n /** Main heading displayed over the image. */\n title: string;\n /** Supporting text displayed below the title. */\n description?: string;\n /**\n * Short labels displayed above the title. Only the first two are rendered.\n * Plain strings render with the default color scheme; use `CarouselSlideTag`\n * objects to set a severity per tag.\n */\n tags?: (string | CarouselSlideTag)[];\n /** Label of the call-to-action button. When omitted, no button is rendered. */\n actionLabel?: string;\n /** Icon name (from the design system IconCatalog) shown in the action button. */\n actionIcon?: string;\n /**\n * Consumer-driven presentation state of the slide.\n * @default 'default'\n */\n state?: CarouselSlideState;\n /** Illustration URL for the error view, forwarded to `tk-fallback-view`. */\n errorImageSrc?: string;\n /** Title of the error view (manual variant only). */\n errorTitle?: string;\n /** Message of the error view (manual variant only). */\n errorDescription?: string;\n}\n\n/**\n * Payload emitted when the active slide changes.\n */\nexport interface CarouselSlideChangeEvent {\n /** Zero-based index of the active slide within the visible slides. */\n index: number;\n /** The slide that became active. */\n slide: CarouselSlide;\n}\n\n/** Autoplay interval, in milliseconds, applied by the autoplay variant. */\nexport const AUTOPLAY_INTERVAL_MS = 7000;\n\n/** Maximum number of tags rendered per slide. */\nexport const MAX_VISIBLE_TAGS = 2;\n\n/** Maximum number of characters of the slide title before truncation. */\nexport const MAX_TITLE_LENGTH = 50;\n\n/** Maximum number of characters of the slide description before truncation. */\nexport const MAX_DESCRIPTION_LENGTH = 140;\n\n/** Maximum number of characters per tag before truncation. */\nexport const MAX_TAG_LENGTH = 20;\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n} from '@angular/core';\n\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { FallbackViewComponent } from '@tekus/design-system/components/fallback-view';\nimport { TagComponent } from '@tekus/design-system/components/tag';\n\nimport {\n CarouselSlide,\n CarouselSlideState,\n CarouselSlideTag,\n MAX_DESCRIPTION_LENGTH,\n MAX_TAG_LENGTH,\n MAX_TITLE_LENGTH,\n MAX_VISIBLE_TAGS,\n} from './carousel.types';\n\nconst truncateWithEllipsis = (text: string, maxLength: number): string =>\n text.length > maxLength ? text.substring(0, maxLength) + '…' : text;\n\n/**\n * @component CarouselItemComponent\n * @description\n * Internal slide renderer for `tk-carousel`. It is not part of the public API\n * of the design system and must only be used by `CarouselComponent`.\n *\n * Renders one of two views depending on the slide state:\n * - `default`: background image with a bottom gradient overlay, up to two\n * tags, a title, a description, and an optional call-to-action button.\n * - `error`: `tk-fallback-view` with an illustration and error messages.\n * Also used when the background image fails to load.\n *\n * Both image and error slides expose a transparent zoom control that emits\n * `slideClick` so the host can open a lightbox (the full-resolution image, or\n * the failure detail for error slides). Plain slides without image are not clickable.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-carousel-item',\n imports: [ButtonComponent, FallbackViewComponent, TagComponent],\n templateUrl: './carousel-item.component.html',\n styleUrl: './carousel-item.component.scss',\n})\nexport class CarouselItemComponent {\n /** Slide data to render. */\n slide = input.required<CarouselSlide>();\n\n /** Whether the slide image failed to load and the error view must be shown. */\n hasError = input<boolean>(false);\n\n /** Emits when the call-to-action button is clicked. */\n actionClick = output<void>();\n\n /** Emits when the background image fails to load. */\n imageError = output<void>();\n\n /** Emits when the slide image is clicked (default state with an image only). */\n slideClick = output<void>();\n\n /** Effective presentation state, combining the slide state and image load failures. */\n state = computed<CarouselSlideState>(() =>\n this.hasError() || this.slide().state === 'error' ? 'error' : 'default'\n );\n\n /** Tags normalized to `CarouselSlideTag` and limited to the maximum allowed by the design. */\n visibleTags = computed<CarouselSlideTag[]>(() => {\n const tags = this.slide().tags ?? [];\n return tags\n .slice(0, MAX_VISIBLE_TAGS)\n .map((tag) => (typeof tag === 'string' ? { value: tag } : tag));\n });\n\n /** Alternative text for the background image, falling back to the title. */\n altText = computed(() => this.slide().imageAlt ?? this.slide().title);\n\n /**\n * Whether the clickable zoom control is rendered. It is shown for slides with\n * an image (to enlarge it) and for error slides (to open the failure detail).\n * Plain slides without image are not clickable.\n */\n showZoom = computed(() => this.state() === 'error' || !!this.slide().imageSrc);\n\n /** Accessible label for the zoom control, adapted to the slide state. */\n zoomLabel = computed(() =>\n this.state() === 'error'\n ? `Ver detalle de ${this.slide().title}`\n : `Ampliar ${this.slide().title}`\n );\n\n /** Title truncated with an ellipsis when it exceeds the maximum length. */\n displayTitle = computed(() =>\n truncateWithEllipsis(this.slide().title, MAX_TITLE_LENGTH)\n );\n\n /** Description truncated with an ellipsis when it exceeds the maximum length. */\n displayDescription = computed(() =>\n truncateWithEllipsis(this.slide().description ?? '', MAX_DESCRIPTION_LENGTH)\n );\n\n /** Error title truncated with an ellipsis, using the same limit as the title. */\n displayErrorTitle = computed(() =>\n truncateWithEllipsis(this.slide().errorTitle ?? '', MAX_TITLE_LENGTH)\n );\n\n /** Error message truncated with an ellipsis, using the same limit as the description. */\n displayErrorDescription = computed(() =>\n truncateWithEllipsis(this.slide().errorDescription ?? '', MAX_DESCRIPTION_LENGTH)\n );\n\n /** Maximum characters per tag, forwarded to `tk-tag`. */\n readonly tagTruncationLimit = MAX_TAG_LENGTH;\n\n onImageError(): void {\n this.imageError.emit();\n }\n\n onActionClick(): void {\n this.actionClick.emit();\n }\n\n onSlideClick(): void {\n this.slideClick.emit();\n }\n}\n","<div\n class=\"carousel-item\"\n [class.carousel-item--error]=\"state() === 'error'\"\n [class.carousel-item--plain]=\"state() === 'default' && !slide().imageSrc\">\n @if (showZoom()) {\n <button\n type=\"button\"\n class=\"carousel-item__zoom\"\n [attr.aria-label]=\"zoomLabel()\"\n (click)=\"onSlideClick()\">\n </button>\n }\n @switch (state()) {\n @case ('error') {\n <output class=\"carousel-item__status\" [title]=\"slide().errorDescription ?? ''\">\n <tk-fallback-view\n [imageSrc]=\"slide().errorImageSrc ?? ''\"\n [illustrationAlt]=\"slide().errorTitle ?? ''\"\n [title]=\"displayErrorTitle()\"\n [message]=\"displayErrorDescription()\">\n </tk-fallback-view>\n </output>\n }\n @default {\n @if (slide().imageSrc) {\n <img\n class=\"carousel-item__image\"\n [src]=\"slide().imageSrc\"\n [alt]=\"altText()\"\n (error)=\"onImageError()\" />\n <div class=\"carousel-item__overlay\" aria-hidden=\"true\"></div>\n }\n <div class=\"carousel-item__content\">\n @if (visibleTags().length > 0) {\n <div class=\"carousel-item__tags\">\n @for (tag of visibleTags(); track tag.value) {\n <tk-tag\n [value]=\"tag.value\"\n [severity]=\"tag.severity ?? 'primary'\"\n [truncationLimit]=\"tagTruncationLimit\">\n </tk-tag>\n }\n </div>\n }\n <div class=\"carousel-item__text\">\n <h2 class=\"carousel-item__title\" [title]=\"slide().title\">{{ displayTitle() }}</h2>\n @if (slide().description) {\n <p class=\"carousel-item__description\" [title]=\"slide().description\">\n {{ displayDescription() }}\n </p>\n }\n </div>\n @if (slide().actionLabel) {\n <div class=\"carousel-item__action\">\n <tk-button\n [label]=\"slide().actionLabel\"\n severity=\"primary\"\n [icon]=\"slide().actionIcon\"\n iconPosition=\"right\"\n [full]=\"true\"\n (clicked)=\"onActionClick()\">\n </tk-button>\n </div>\n }\n </div>\n }\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { Carousel, CarouselModule, CarouselPageEvent } from 'primeng/carousel';\nimport { IconComponent } from '@tekus/design-system/components/icon';\n\nimport { CarouselItemComponent } from './carousel-item.component';\nimport {\n AUTOPLAY_INTERVAL_MS,\n CarouselIndicatorType,\n CarouselSlide,\n CarouselSlideChangeEvent,\n CarouselVariant,\n} from './carousel.types';\n\n/**\n * @component CarouselComponent\n * @description\n * Adaptive carousel that displays a sequence of slides one at a time, each\n * with a background image, up to two tags, a title, a description, and an\n * optional call-to-action button. It wraps PrimeNG's `p-carousel` with the\n * Tekus design system look.\n *\n * The rotation is always an infinite loop: after the last slide, next returns\n * to the first one.\n *\n * Variants (`variant` input):\n * - `'manual'` (default): the user navigates with arrows and indicator; if a\n * slide image fails to load, an error fallback is shown in its place.\n * - `'autoplay'`: the rotation advances automatically every 7 seconds with\n * swipe gestures enabled; slides whose image fails to load are removed\n * from the rotation silently (unattended usage).\n *\n * Indicators (`indicator` input):\n * - `'dots'` (default): dot indicators overlaid at the bottom of the slide.\n * - `'thumbnails'`: clickable image thumbnails rendered below the slide.\n *\n * The slide height can be customized with the `--tk-carousel-height` CSS\n * variable (defaults to `28.125rem`).\n *\n * @usage\n * ### Manual navigation (default)\n * ```html\n * <tk-carousel\n * [slides]=\"slides\"\n * (slideChange)=\"onSlideChange($event)\"\n * (actionClick)=\"onActionClick($event)\"\n * (slideClick)=\"openLightbox($event)\">\n * </tk-carousel>\n * ```\n *\n * ### Autoplay with thumbnails\n * ```html\n * <tk-carousel\n * [slides]=\"slides\"\n * variant=\"autoplay\"\n * indicator=\"thumbnails\">\n * </tk-carousel>\n * ```\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-carousel',\n imports: [CarouselModule, CarouselItemComponent, IconComponent],\n templateUrl: './carousel.component.html',\n styleUrl: './carousel.component.scss',\n})\nexport class CarouselComponent {\n /** Slides to display. Each slide must have a stable unique `id`. */\n slides = input.required<CarouselSlide[]>();\n\n /**\n * Behavioral preset of the carousel.\n * @default 'manual'\n */\n variant = input<CarouselVariant>('manual');\n\n /**\n * Type of position indicator.\n * @default 'dots'\n */\n indicator = input<CarouselIndicatorType>('dots');\n\n /** Emits when the active slide changes, via arrows, indicator, swipe, or autoplay. */\n slideChange = output<CarouselSlideChangeEvent>();\n\n /** Emits the slide whose call-to-action button was clicked. */\n actionClick = output<CarouselSlide>();\n\n /** Emits the slide whose image was clicked, so consumers can open a lightbox. */\n slideClick = output<CarouselSlide>();\n\n /** Reference to the underlying PrimeNG carousel, used for thumbnail navigation. */\n primeCarousel = viewChild(Carousel);\n\n /** Zero-based index of the active slide within the visible slides. */\n currentIndex = signal(0);\n\n /** Ids of the slides whose image failed to load. */\n failedSlideIds = signal<ReadonlySet<CarouselSlide['id']>>(new Set());\n\n /** Whether the autoplay preset is active. */\n isAutoplay = computed(() => this.variant() === 'autoplay');\n\n /** Autoplay interval mapped from the variant preset. `0` disables autoplay. */\n autoplayInterval = computed(() =>\n this.isAutoplay() ? AUTOPLAY_INTERVAL_MS : 0\n );\n\n /**\n * Slides currently part of the rotation. The autoplay variant excludes\n * slides whose image failed to load; the manual variant keeps them and\n * shows an error fallback instead.\n */\n visibleSlides = computed(() => {\n const failed = this.failedSlideIds();\n const slides = this.slides();\n if (!this.isAutoplay() || failed.size === 0) {\n return slides;\n }\n return slides.filter((slide) => !failed.has(slide.id));\n });\n\n /**\n * Whether the navigation controls (arrows and indicators) are rendered.\n * With a single visible slide there is nowhere to navigate, so they are hidden.\n */\n showNavigation = computed(() => this.visibleSlides().length > 1);\n\n /** Whether the dot indicator is rendered. */\n showDots = computed(() => this.indicator() === 'dots' && this.showNavigation());\n\n /** Whether the thumbnail indicator is rendered. */\n showThumbnails = computed(\n () => this.indicator() === 'thumbnails' && this.showNavigation()\n );\n\n onPage(event: CarouselPageEvent): void {\n const index = event.page ?? 0;\n this.currentIndex.set(index);\n const slide = this.visibleSlides()[index];\n if (slide) {\n this.slideChange.emit({ index, slide });\n }\n }\n\n onThumbnailClick(event: MouseEvent, index: number): void {\n this.primeCarousel()?.onDotClick(event, index);\n }\n\n onImageError(slide: CarouselSlide): void {\n this.failedSlideIds.update((failed) => new Set(failed).add(slide.id));\n }\n\n onActionClick(slide: CarouselSlide): void {\n this.actionClick.emit(slide);\n }\n\n onSlideClick(slide: CarouselSlide): void {\n this.slideClick.emit(slide);\n }\n\n hasSlideError(slide: CarouselSlide): boolean {\n return slide.state === 'error' || this.failedSlideIds().has(slide.id);\n }\n}\n","<div class=\"carousel\">\n <p-carousel\n [value]=\"visibleSlides()\"\n [numVisible]=\"1\"\n [numScroll]=\"1\"\n [circular]=\"showNavigation()\"\n [autoplayInterval]=\"autoplayInterval()\"\n [showIndicators]=\"showDots()\"\n [showNavigators]=\"showNavigation()\"\n (onPage)=\"onPage($event)\">\n <ng-template pTemplate=\"item\" let-slide>\n <tk-carousel-item\n [slide]=\"slide\"\n [hasError]=\"failedSlideIds().has(slide.id)\"\n (imageError)=\"onImageError(slide)\"\n (actionClick)=\"onActionClick(slide)\"\n (slideClick)=\"onSlideClick(slide)\">\n </tk-carousel-item>\n </ng-template>\n <ng-template pTemplate=\"previousicon\">\n <tk-icon icon=\"angle-left\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n <ng-template pTemplate=\"nexticon\">\n <tk-icon icon=\"angle-right\" styleIcon=\"solid\"></tk-icon>\n </ng-template>\n </p-carousel>\n\n @if (showThumbnails()) {\n <div class=\"carousel__thumbnails\" role=\"tablist\">\n @for (slide of visibleSlides(); track slide.id) {\n <button\n type=\"button\"\n class=\"carousel__thumbnail\"\n [class.carousel__thumbnail--active]=\"currentIndex() === $index\"\n role=\"tab\"\n [attr.aria-selected]=\"currentIndex() === $index\"\n [attr.aria-label]=\"slide.title\"\n (click)=\"onThumbnailClick($event, $index)\">\n @if (hasSlideError(slide)) {\n <span class=\"carousel__thumbnail-placeholder carousel__thumbnail-placeholder--error\">\n <tk-icon icon=\"triangle-exclamation\" styleIcon=\"regular\"></tk-icon>\n </span>\n } @else if (!slide.imageSrc) {\n <span class=\"carousel__thumbnail-placeholder\"></span>\n } @else {\n <img class=\"carousel__thumbnail-image\" [src]=\"slide.imageSrc\" alt=\"\" />\n }\n </button>\n }\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { ButtonComponent } from '@tekus/design-system/components/button';
4
+ import { DropdownComponent } from '@tekus/design-system/components/dropdown';
5
+
6
+ class HeaderComponent {
7
+ constructor() {
8
+ this.logoSrc = input(...(ngDevMode ? [undefined, { debugName: "logoSrc" }] : /* istanbul ignore next */ []));
9
+ this.logoAlt = input('Logo', ...(ngDevMode ? [{ debugName: "logoAlt" }] : /* istanbul ignore next */ []));
10
+ this.leftActions = input([], ...(ngDevMode ? [{ debugName: "leftActions" }] : /* istanbul ignore next */ []));
11
+ this.rightActions = input([], ...(ngDevMode ? [{ debugName: "rightActions" }] : /* istanbul ignore next */ []));
12
+ }
13
+ isDropdown(action) {
14
+ return action.type === 'dropdown';
15
+ }
16
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
17
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: HeaderComponent, isStandalone: true, selector: "tk-header", inputs: { logoSrc: { classPropertyName: "logoSrc", publicName: "logoSrc", isSignal: true, isRequired: false, transformFunction: null }, logoAlt: { classPropertyName: "logoAlt", publicName: "logoAlt", isSignal: true, isRequired: false, transformFunction: null }, leftActions: { classPropertyName: "leftActions", publicName: "leftActions", isSignal: true, isRequired: false, transformFunction: null }, rightActions: { classPropertyName: "rightActions", publicName: "rightActions", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "tk-header" }, ngImport: i0, template: "<div class=\"tk-header__left\">\n @for (action of leftActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n\n@if (logoSrc()) {\n <div class=\"tk-header__content\">\n <img class=\"tk-header__logo\" [src]=\"logoSrc()\" [alt]=\"logoAlt()\" />\n </div>\n}\n\n<div class=\"tk-header__right\">\n @for (action of rightActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;background-color:var(--tk-color-background-soft, #f2f1f1);padding:var(--tk-spacing-padding-s, .5rem) var(--tk-spacing-padding-m, 1rem);width:100%;height:3.5rem;box-sizing:border-box}.tk-header__left{display:flex;align-items:center;flex:1 0 0;min-width:0}.tk-header__content{display:flex;align-items:center;flex-shrink:0}.tk-header__logo{height:2rem;width:auto;display:block}.tk-header__right{display:flex;align-items:center;justify-content:flex-end;flex:1 0 0;min-width:0}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "iconPosition", "tooltipText", "full", "ariaLabel", "size"], outputs: ["clicked"] }, { kind: "component", type: DropdownComponent, selector: "tk-dropdown", inputs: ["model", "icon", "label", "iconPosition", "size", "disabled", "tooltip", "tooltipPosition"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18
+ }
19
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HeaderComponent, decorators: [{
20
+ type: Component,
21
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-header', imports: [ButtonComponent, DropdownComponent], host: { class: 'tk-header' }, template: "<div class=\"tk-header__left\">\n @for (action of leftActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n\n@if (logoSrc()) {\n <div class=\"tk-header__content\">\n <img class=\"tk-header__logo\" [src]=\"logoSrc()\" [alt]=\"logoAlt()\" />\n </div>\n}\n\n<div class=\"tk-header__right\">\n @for (action of rightActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n", styles: [":host{display:flex;align-items:center;justify-content:space-between;background-color:var(--tk-color-background-soft, #f2f1f1);padding:var(--tk-spacing-padding-s, .5rem) var(--tk-spacing-padding-m, 1rem);width:100%;height:3.5rem;box-sizing:border-box}.tk-header__left{display:flex;align-items:center;flex:1 0 0;min-width:0}.tk-header__content{display:flex;align-items:center;flex-shrink:0}.tk-header__logo{height:2rem;width:auto;display:block}.tk-header__right{display:flex;align-items:center;justify-content:flex-end;flex:1 0 0;min-width:0}\n"] }]
22
+ }], propDecorators: { logoSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoSrc", required: false }] }], logoAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoAlt", required: false }] }], leftActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftActions", required: false }] }], rightActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rightActions", required: false }] }] } });
23
+
24
+ /**
25
+ * Generated bundle index. Do not edit.
26
+ */
27
+
28
+ export { HeaderComponent };
29
+ //# sourceMappingURL=tekus-design-system-components-header.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tekus-design-system-components-header.mjs","sources":["../../../projects/design-system/components/header/src/header.component.ts","../../../projects/design-system/components/header/src/header.component.html","../../../projects/design-system/components/header/tekus-design-system-components-header.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DropdownComponent } from '@tekus/design-system/components/dropdown';\nimport { TkHeaderAnyAction, TkHeaderDropdownAction } from './header.types';\n\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-header',\n imports: [ButtonComponent, DropdownComponent],\n templateUrl: './header.component.html',\n styleUrl: './header.component.scss',\n host: { class: 'tk-header' },\n})\nexport class HeaderComponent {\n logoSrc = input<string>();\n logoAlt = input<string>('Logo');\n leftActions = input<TkHeaderAnyAction[]>([]);\n rightActions = input<TkHeaderAnyAction[]>([]);\n\n protected isDropdown(action: TkHeaderAnyAction): action is TkHeaderDropdownAction {\n return (action as TkHeaderDropdownAction).type === 'dropdown';\n }\n}\n","<div class=\"tk-header__left\">\n @for (action of leftActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n\n@if (logoSrc()) {\n <div class=\"tk-header__content\">\n <img class=\"tk-header__logo\" [src]=\"logoSrc()\" [alt]=\"logoAlt()\" />\n </div>\n}\n\n<div class=\"tk-header__right\">\n @for (action of rightActions(); track $index) {\n @if (isDropdown(action)) {\n <tk-dropdown\n [model]=\"action.model\"\n [icon]=\"action.icon ?? 'ellipsis-vertical'\"\n [label]=\"action.label\"\n [iconPosition]=\"action.iconPosition ?? 'left'\"\n [size]=\"action.size\"\n [disabled]=\"action.disabled ?? false\"\n [tooltip]=\"action.tooltip\">\n </tk-dropdown>\n } @else {\n <tk-button\n variant=\"text\"\n severity=\"secondary\"\n [icon]=\"action.icon\"\n [tooltipText]=\"action.label\"\n [disabled]=\"action.disabled ?? false\"\n (clicked)=\"action.action()\">\n </tk-button>\n }\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;MAaa,eAAe,CAAA;AAR5B,IAAA,WAAA,GAAA;QASE,IAAA,CAAA,OAAO,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,SAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAU;AACzB,QAAA,IAAA,CAAA,OAAO,GAAG,KAAK,CAAS,MAAM,8EAAC;AAC/B,QAAA,IAAA,CAAA,WAAW,GAAG,KAAK,CAAsB,EAAE,kFAAC;AAC5C,QAAA,IAAA,CAAA,YAAY,GAAG,KAAK,CAAsB,EAAE,mFAAC;AAK9C,IAAA;AAHW,IAAA,UAAU,CAAC,MAAyB,EAAA;AAC5C,QAAA,OAAQ,MAAiC,CAAC,IAAI,KAAK,UAAU;IAC/D;+GARW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAf,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,WAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECb5B,ynDAuDA,EAAA,MAAA,EAAA,CAAA,giBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED/CY,eAAe,sNAAE,iBAAiB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,cAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,iBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAKjC,eAAe,EAAA,UAAA,EAAA,CAAA;kBAR3B,SAAS;AACS,YAAA,IAAA,EAAA,CAAA,EAAA,eAAA,EAAA,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,WAAW,WACZ,CAAC,eAAe,EAAE,iBAAiB,CAAC,EAAA,IAAA,EAGvC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,ynDAAA,EAAA,MAAA,EAAA,CAAA,giBAAA,CAAA,EAAA;;;AEX9B;;AAEG;;;;"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ElementRef, Injector, viewChild, ViewContainerRef, input, model, computed, output, effect, untracked, afterEveryRender, ChangeDetectionStrategy, Component, ApplicationRef, createComponent, Injectable } from '@angular/core';
2
+ import { inject, ElementRef, Injector, viewChild, ViewContainerRef, input, model, computed, output, afterEveryRender, effect, untracked, ChangeDetectionStrategy, Component, ApplicationRef, createComponent, Injectable } from '@angular/core';
3
3
  import { ButtonComponent } from '@tekus/design-system/components/button';
4
4
  import * as i1 from 'primeng/dialog';
5
5
  import { DialogModule } from 'primeng/dialog';
@@ -16,9 +16,6 @@ import * as i2 from 'primeng/api';
16
16
  */
17
17
  class ModalComponent {
18
18
  constructor() {
19
- /**
20
- * @summary Orchestrates the reactive dynamic lifecycle.
21
- */
22
19
  this.elementRef = inject(ElementRef);
23
20
  this.injector = inject(Injector);
24
21
  this.contentHost = viewChild('contentHost', { ...(ngDevMode ? { debugName: "contentHost" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
@@ -74,6 +71,15 @@ class ModalComponent {
74
71
  }
75
72
  }, ...(ngDevMode ? [{ debugName: "modalMaxWidth" }] : /* istanbul ignore next */ []));
76
73
  this.wasOpened = false;
74
+ this.registerContentLifecycleEffect();
75
+ this.registerDataSyncEffect();
76
+ afterEveryRender(() => this.checkScroll());
77
+ }
78
+ /**
79
+ * @summary Orchestrates the reactive dynamic lifecycle.
80
+ * @private
81
+ */
82
+ registerContentLifecycleEffect() {
77
83
  effect(() => {
78
84
  const opened = this.isOpened();
79
85
  const host = this.contentHost();
@@ -87,13 +93,15 @@ class ModalComponent {
87
93
  }
88
94
  });
89
95
  });
96
+ }
97
+ /**
98
+ * @private
99
+ */
100
+ registerDataSyncEffect() {
90
101
  effect(() => {
91
102
  const currentData = this.data();
92
103
  untracked(() => this.syncDynamicInputs(currentData));
93
104
  });
94
- afterEveryRender(() => {
95
- this.checkScroll();
96
- });
97
105
  }
98
106
  ngOnDestroy() {
99
107
  this.detachDynamicContent();
@@ -105,25 +113,32 @@ class ModalComponent {
105
113
  attachDynamicContent() {
106
114
  const type = this.content();
107
115
  const host = this.contentHost();
108
- if (!type || typeof type === 'string' || !host)
116
+ if (!type || typeof type === 'string' || !host) {
109
117
  return;
118
+ }
110
119
  this.detachDynamicContent();
111
- const customInjector = Injector.create({
112
- providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],
113
- parent: this.injector,
114
- });
115
120
  this.componentRef = host.createComponent(type, {
116
- injector: customInjector,
121
+ injector: this.createContentInjector(),
117
122
  });
118
123
  this.syncDynamicInputs(this.data());
119
124
  }
125
+ /**
126
+ * @private
127
+ */
128
+ createContentInjector() {
129
+ return Injector.create({
130
+ providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],
131
+ parent: this.injector,
132
+ });
133
+ }
120
134
  /**
121
135
  * @summary Synchronizes incoming data record with the dynamic instance @Inputs.
122
136
  * @private
123
137
  */
124
138
  syncDynamicInputs(data) {
125
- if (!this.componentRef)
139
+ if (!this.componentRef) {
126
140
  return;
141
+ }
127
142
  Object.entries(data).forEach(([key, value]) => {
128
143
  this.componentRef?.setInput(key, value);
129
144
  });
@@ -169,21 +184,25 @@ class ModalComponent {
169
184
  instance?.onBlockedClose?.();
170
185
  return;
171
186
  }
172
- const configInterceptor = this.interceptor();
173
- if (configInterceptor) {
174
- const interceptorResult = configInterceptor();
175
- this.evaluateCanClose(interceptorResult, (canCloseInterceptor) => {
176
- if (canCloseInterceptor) {
177
- this.executeClosure(returnValue, hasReturnValue);
178
- }
179
- else {
180
- instance?.onBlockedClose?.();
181
- }
182
- });
183
- }
184
- else {
185
- this.executeClosure(returnValue, hasReturnValue);
187
+ this.resolveInterceptorAndClose(instance, returnValue, hasReturnValue);
188
+ });
189
+ }
190
+ /**
191
+ * @summary Evaluates the optional close interceptor, then executes closure.
192
+ * @private
193
+ */
194
+ resolveInterceptorAndClose(instance, returnValue, hasReturnValue) {
195
+ const configInterceptor = this.interceptor();
196
+ if (!configInterceptor) {
197
+ this.executeClosure(returnValue, hasReturnValue);
198
+ return;
199
+ }
200
+ this.evaluateCanClose(configInterceptor(), (canCloseInterceptor) => {
201
+ if (!canCloseInterceptor) {
202
+ instance?.onBlockedClose?.();
203
+ return;
186
204
  }
205
+ this.executeClosure(returnValue, hasReturnValue);
187
206
  });
188
207
  }
189
208
  /**
@@ -248,8 +267,9 @@ class ModalComponent {
248
267
  * @summary Handles actions triggered by footer buttons.
249
268
  */
250
269
  handleAction(action, returnValue, preventClose = false) {
251
- if (action)
270
+ if (action) {
252
271
  action();
272
+ }
253
273
  if (!preventClose) {
254
274
  this.tryClose(returnValue);
255
275
  }