@siemens/element-ng 51.3.0 → 51.5.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.
Files changed (98) hide show
  1. package/fesm2022/siemens-element-ng-about.mjs +2 -2
  2. package/fesm2022/siemens-element-ng-about.mjs.map +1 -1
  3. package/fesm2022/siemens-element-ng-ag-grid.mjs +5 -4
  4. package/fesm2022/siemens-element-ng-ag-grid.mjs.map +1 -1
  5. package/fesm2022/siemens-element-ng-breadcrumb.mjs +20 -71
  6. package/fesm2022/siemens-element-ng-breadcrumb.mjs.map +1 -1
  7. package/fesm2022/siemens-element-ng-carousel.mjs +6 -4
  8. package/fesm2022/siemens-element-ng-carousel.mjs.map +1 -1
  9. package/fesm2022/siemens-element-ng-chat-messages.mjs +3 -3
  10. package/fesm2022/siemens-element-ng-chat-messages.mjs.map +1 -1
  11. package/fesm2022/siemens-element-ng-common.mjs +16 -1
  12. package/fesm2022/siemens-element-ng-common.mjs.map +1 -1
  13. package/fesm2022/siemens-element-ng-dashboard.mjs +2 -3
  14. package/fesm2022/siemens-element-ng-dashboard.mjs.map +1 -1
  15. package/fesm2022/siemens-element-ng-datatable.mjs +1 -1
  16. package/fesm2022/siemens-element-ng-datatable.mjs.map +1 -1
  17. package/fesm2022/siemens-element-ng-empty-state.mjs +2 -2
  18. package/fesm2022/siemens-element-ng-empty-state.mjs.map +1 -1
  19. package/fesm2022/siemens-element-ng-filtered-search.mjs +255 -160
  20. package/fesm2022/siemens-element-ng-filtered-search.mjs.map +1 -1
  21. package/fesm2022/siemens-element-ng-formly.mjs +13 -9
  22. package/fesm2022/siemens-element-ng-formly.mjs.map +1 -1
  23. package/fesm2022/siemens-element-ng-header-dropdown.mjs +2 -2
  24. package/fesm2022/siemens-element-ng-header-dropdown.mjs.map +1 -1
  25. package/fesm2022/siemens-element-ng-list-details.mjs +7 -4
  26. package/fesm2022/siemens-element-ng-list-details.mjs.map +1 -1
  27. package/fesm2022/siemens-element-ng-loading-spinner.mjs +21 -7
  28. package/fesm2022/siemens-element-ng-loading-spinner.mjs.map +1 -1
  29. package/fesm2022/siemens-element-ng-maplibre.mjs +293 -10
  30. package/fesm2022/siemens-element-ng-maplibre.mjs.map +1 -1
  31. package/fesm2022/siemens-element-ng-markdown-extensions-katex.mjs +6 -3
  32. package/fesm2022/siemens-element-ng-markdown-extensions-katex.mjs.map +1 -1
  33. package/fesm2022/siemens-element-ng-markdown-extensions-mermaid.mjs +9 -0
  34. package/fesm2022/siemens-element-ng-markdown-extensions-mermaid.mjs.map +1 -1
  35. package/fesm2022/siemens-element-ng-markdown.mjs +6 -2
  36. package/fesm2022/siemens-element-ng-markdown.mjs.map +1 -1
  37. package/fesm2022/siemens-element-ng-menu.mjs +6 -6
  38. package/fesm2022/siemens-element-ng-menu.mjs.map +1 -1
  39. package/fesm2022/siemens-element-ng-modal.mjs +4 -3
  40. package/fesm2022/siemens-element-ng-modal.mjs.map +1 -1
  41. package/fesm2022/siemens-element-ng-navbar-vertical-next.mjs +10 -4
  42. package/fesm2022/siemens-element-ng-navbar-vertical-next.mjs.map +1 -1
  43. package/fesm2022/siemens-element-ng-navbar-vertical.mjs +12 -6
  44. package/fesm2022/siemens-element-ng-navbar-vertical.mjs.map +1 -1
  45. package/fesm2022/siemens-element-ng-pills-input.mjs +5 -4
  46. package/fesm2022/siemens-element-ng-pills-input.mjs.map +1 -1
  47. package/fesm2022/siemens-element-ng-popover-legacy.mjs +1 -1
  48. package/fesm2022/siemens-element-ng-popover-legacy.mjs.map +1 -1
  49. package/fesm2022/siemens-element-ng-popover.mjs +36 -7
  50. package/fesm2022/siemens-element-ng-popover.mjs.map +1 -1
  51. package/fesm2022/siemens-element-ng-result-details-list.mjs +1 -1
  52. package/fesm2022/siemens-element-ng-result-details-list.mjs.map +1 -1
  53. package/fesm2022/siemens-element-ng-select.mjs +3 -3
  54. package/fesm2022/siemens-element-ng-select.mjs.map +1 -1
  55. package/fesm2022/siemens-element-ng-shadow-root.mjs +54 -1
  56. package/fesm2022/siemens-element-ng-shadow-root.mjs.map +1 -1
  57. package/fesm2022/siemens-element-ng-side-panel.mjs +17 -7
  58. package/fesm2022/siemens-element-ng-side-panel.mjs.map +1 -1
  59. package/fesm2022/siemens-element-ng-skip-links.mjs +18 -4
  60. package/fesm2022/siemens-element-ng-skip-links.mjs.map +1 -1
  61. package/fesm2022/siemens-element-ng-source-chip.mjs +1 -1
  62. package/fesm2022/siemens-element-ng-source-chip.mjs.map +1 -1
  63. package/fesm2022/siemens-element-ng-split.mjs +2 -2
  64. package/fesm2022/siemens-element-ng-split.mjs.map +1 -1
  65. package/fesm2022/siemens-element-ng-status-bar.mjs +2 -2
  66. package/fesm2022/siemens-element-ng-status-bar.mjs.map +1 -1
  67. package/fesm2022/siemens-element-ng-theme.mjs +59 -23
  68. package/fesm2022/siemens-element-ng-theme.mjs.map +1 -1
  69. package/fesm2022/siemens-element-ng-tooltip.mjs +83 -11
  70. package/fesm2022/siemens-element-ng-tooltip.mjs.map +1 -1
  71. package/fesm2022/siemens-element-ng-translate.mjs.map +1 -1
  72. package/fesm2022/siemens-element-ng-tree-view.mjs +3 -4
  73. package/fesm2022/siemens-element-ng-tree-view.mjs.map +1 -1
  74. package/fesm2022/siemens-element-ng-typeahead.mjs +2 -2
  75. package/fesm2022/siemens-element-ng-typeahead.mjs.map +1 -1
  76. package/maplibre/styles/maplibre-gl.scss +4 -0
  77. package/package.json +7 -7
  78. package/schematics/utils/ts-compiler-host.js +21 -0
  79. package/template-i18n.json +7 -0
  80. package/types/siemens-element-ng-ag-grid.d.ts +1 -0
  81. package/types/siemens-element-ng-breadcrumb.d.ts +3 -6
  82. package/types/siemens-element-ng-common.d.ts +28 -3
  83. package/types/siemens-element-ng-dashboard.d.ts +0 -1
  84. package/types/siemens-element-ng-filtered-search.d.ts +26 -10
  85. package/types/siemens-element-ng-list-details.d.ts +2 -0
  86. package/types/siemens-element-ng-loading-spinner.d.ts +11 -4
  87. package/types/siemens-element-ng-maplibre.d.ts +112 -5
  88. package/types/siemens-element-ng-markdown-extensions-katex.d.ts +4 -1
  89. package/types/siemens-element-ng-markdown-extensions-mermaid.d.ts +9 -0
  90. package/types/siemens-element-ng-navbar-vertical-next.d.ts +2 -1
  91. package/types/siemens-element-ng-navbar-vertical.d.ts +2 -2
  92. package/types/siemens-element-ng-popover.d.ts +19 -1
  93. package/types/siemens-element-ng-shadow-root.d.ts +16 -1
  94. package/types/siemens-element-ng-side-panel.d.ts +7 -2
  95. package/types/siemens-element-ng-skip-links.d.ts +4 -2
  96. package/types/siemens-element-ng-theme.d.ts +35 -7
  97. package/types/siemens-element-ng-tooltip.d.ts +14 -1
  98. package/types/siemens-element-ng-translate.d.ts +7 -0
@@ -1,10 +1,13 @@
1
+ import { CdkMenuTrigger } from '@angular/cdk/menu';
1
2
  import { NgTemplateOutlet } from '@angular/common';
2
3
  import * as i0 from '@angular/core';
3
- import { Directive, input, booleanAttribute, viewChild, viewChildren, inject, ChangeDetectorRef, HostListener, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
4
+ import { Directive, input, booleanAttribute, viewChild, viewChildren, inject, ChangeDetectorRef, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
4
5
  import { elementRight2, elementBreadcrumbRoot } from '@siemens/element-icons';
5
6
  import { addIcons, SiIconComponent } from '@siemens/element-ng/icon';
6
7
  import { SiLinkDirective } from '@siemens/element-ng/link';
8
+ import { SiMenuDirective, SiMenuItemComponent } from '@siemens/element-ng/menu';
7
9
  import { SiResizeObserverDirective } from '@siemens/element-ng/resize-observer';
10
+ import { SiTooltipOverflowDirective } from '@siemens/element-ng/tooltip';
8
11
  import { t, injectSiTranslateService, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
9
12
  import { merge, of } from 'rxjs';
10
13
  import { switchMap } from 'rxjs/operators';
@@ -33,22 +36,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
33
36
  * Defines how many items should be displayed at the end of the breadcrumb if possible.
34
37
  */
35
38
  const NUMBER_OF_SHOWN_ITEMS_AT_END = 2;
36
- /**
37
- * Defines how long a display item can be without it being shortened.
38
- * Cannot be lower than 4.
39
- * If this is 0, titles will not be shortened
40
- */
41
- const ITEM_MAX_LENGTH = 30;
42
- /**
43
- * Defines how many characters of an item are always displayed in the beginning.
44
- * Must be at least 2 less than ITEM_MAX_LENGTH
45
- */
46
- const ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING = 10;
47
39
  /**
48
40
  * Defines the width of the root icon in pixels.
49
41
  */
50
42
  const ROOT_ICON_WIDTH = 24;
51
- let controlIdCounter = 1;
52
43
  class SiBreadcrumbComponent {
53
44
  /** Array of breadcrumb items. */
54
45
  items = input.required(/* @ts-ignore */
@@ -76,15 +67,14 @@ class SiBreadcrumbComponent {
76
67
  itemsHidden = [];
77
68
  breadcrumbShortened = false;
78
69
  ellipsesLevel = 0;
79
- // Record to allow for -1 (root).
80
- breadcrumbDropdownOpen = undefined;
81
- addExpandDropdown = false;
82
- controlId = `__si-breadcrumb-${controlIdCounter++}-`;
70
+ hiddenItemsLabel = t(() => $localize `:@@SI_BREADCRUMB.HIDDEN_ITEMS:Hidden breadcrumb items`);
83
71
  icons = addIcons({ elementBreadcrumbRoot, elementRight2 });
84
72
  breadcrumbElement = viewChild.required('breadcrumb', /* @ts-ignore */
85
73
  ...(ngDevMode ? [{ debugName: "breadcrumbElement" }] : /* istanbul ignore next */ []));
86
74
  breadcrumbElements = viewChildren('breadcrumbItem', /* @ts-ignore */
87
75
  ...(ngDevMode ? [{ debugName: "breadcrumbElements" }] : /* istanbul ignore next */ []));
76
+ breadcrumbMenu = viewChild(CdkMenuTrigger, /* @ts-ignore */
77
+ ...(ngDevMode ? [{ debugName: "breadcrumbMenu" }] : /* istanbul ignore next */ []));
88
78
  changeDetector = inject(ChangeDetectorRef);
89
79
  translate = injectSiTranslateService();
90
80
  ngOnChanges() {
@@ -101,29 +91,11 @@ class SiBreadcrumbComponent {
101
91
  this.translationSubscription = merge(this.translate.translationChange, of(undefined))
102
92
  .pipe(switchMap(() => this.translate.translateAsync(this.items().map(item => item.title))))
103
93
  .subscribe(translatedTitles => {
104
- // Add the level to the items and check if they need to be shortened.
105
- // If they need to be shortened, shorten them at a convenient place.
106
- // Set the lastItem tag to true for the last item
94
+ // Add the level and mark the last item, keeping the full translated titles.
107
95
  let counter = -1;
108
96
  const enumeratedItems = this.items().map(item => {
109
97
  counter++;
110
98
  const title = translatedTitles[item.title];
111
- let shortened = false;
112
- let shortenedTitle = title;
113
- // If this is not the last item and the title too long, shorten the title
114
- if (counter !== this.numberOfItems - 1 && title && title.length > ITEM_MAX_LENGTH) {
115
- shortened = true;
116
- // This regex gets the last space, dash or underscore.
117
- const regexMatch = title
118
- .slice(ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING, ITEM_MAX_LENGTH - 2)
119
- .match(/^.*[- _](?=.*?$)/);
120
- if (regexMatch) {
121
- shortenedTitle = title.slice(0, ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING + regexMatch[0].length - 1);
122
- }
123
- else {
124
- shortenedTitle = title.slice(0, ITEM_MAX_LENGTH - 3);
125
- }
126
- }
127
99
  // If the root element should be displayed as text, set level not to 0.
128
100
  // This is used to distinguish in the template between icon and text.
129
101
  const level = counter === 0 && this.showRootAsText() ? -1 : counter;
@@ -132,15 +104,12 @@ class SiBreadcrumbComponent {
132
104
  title,
133
105
  level,
134
106
  hide: false,
135
- shortened,
136
- shortenedTitle,
137
107
  lastItem: counter === this.numberOfItems - 1
138
108
  };
139
109
  });
140
110
  this.itemsShown = enumeratedItems;
141
111
  this.itemsHidden = [];
142
112
  this.breadcrumbShortened = false;
143
- this.breadcrumbDropdownOpen = undefined;
144
113
  this.itemsProcessed = true;
145
114
  this.resetBreadcrumb();
146
115
  });
@@ -149,50 +118,29 @@ class SiBreadcrumbComponent {
149
118
  this.itemsShown = [];
150
119
  this.itemsHidden = [];
151
120
  this.breadcrumbShortened = false;
152
- this.breadcrumbDropdownOpen = undefined;
153
121
  this.itemsProcessed = true;
154
122
  this.resetBreadcrumb();
155
123
  }
156
124
  }
157
- /*
158
- * Toggle dropdown (on click of ellipses), either for
159
- * the general dropdown list if itemLevel is at ellipsesLevel
160
- * or otherwise the name expansion at the specified item level.
161
- * Close any open dropdown before opening a new one.
162
- */
163
- toggleBreadcrumbDropdown(itemLevel) {
164
- this.breadcrumbDropdownOpen = this.breadcrumbDropdownOpen === itemLevel ? undefined : itemLevel;
165
- }
166
- // Close dropdown on click anywhere else
167
- documentClick(targetElement) {
168
- if (this.breadcrumbDropdownOpen) {
169
- if (!this.breadcrumbElement().nativeElement.contains(targetElement)) {
170
- // Close all dropdowns.
171
- this.breadcrumbDropdownOpen = undefined;
172
- }
173
- }
174
- }
175
125
  resetBreadcrumb() {
126
+ this.breadcrumbMenu()?.close();
176
127
  if (this.itemsProcessed) {
177
128
  this.numberOfItems = this.items().length;
178
129
  // Add an additional the ellipses item to the end of the shownItems (breadcrumb items).
179
- // Disable addExpandDropdown for now, to make every item a proper SiBreadcrumbItemComponent.
180
- const ellipsesItem = { title: '...', level: this.numberOfItems, shortenedTitle: '' };
130
+ const ellipsesItem = { title: '...', level: this.numberOfItems };
181
131
  this.itemsShown.push(ellipsesItem);
182
132
  if (this.breadcrumbShortened) {
183
- // If the breadcrumb was shortened before, remove the ellipses and add back itemsHidden (breadcrumb dropdown items).
133
+ // If the breadcrumb was shortened before, remove the ellipses and add back itemsHidden (breadcrumb menu items).
184
134
  this.breadcrumbShortened = false;
185
135
  this.itemsShown.splice(this.ellipsesLevel, 1, ...this.itemsHidden);
186
136
  this.itemsHidden = [];
187
137
  }
188
- this.addExpandDropdown = false;
189
138
  // Wait for the next change detection cycle to measure the updated item length.
190
139
  this.changeDetector.detectChanges();
191
140
  this.calculateBreadcrumb();
192
141
  }
193
142
  }
194
143
  calculateBreadcrumb() {
195
- this.addExpandDropdown = true;
196
144
  const maxWidth = this.breadcrumbElement().nativeElement.clientWidth;
197
145
  const breadcrumbElementsList = this.breadcrumbElements().map(item => item);
198
146
  // Measure the length of the last additional ellipses item, then remove it from itemsShown (breadcrumb items).
@@ -248,33 +196,34 @@ class SiBreadcrumbComponent {
248
196
  }
249
197
  }
250
198
  });
251
- // If breadcrumbShortened is true, move the items that do not fit to itemsHidden (breadcrumb dropdown items) and add ellipses item.
199
+ // If breadcrumbShortened is true, move the items that do not fit to itemsHidden (breadcrumb menu items) and add ellipses item.
252
200
  if (this.breadcrumbShortened) {
253
201
  this.ellipsesLevel = counter;
254
202
  this.itemsHidden = this.itemsShown.slice(this.ellipsesLevel, reverseCounter);
255
- const ellipsesItem = { title: '...', level: this.ellipsesLevel, shortenedTitle: '' };
203
+ const ellipsesItem = { title: '...', level: this.ellipsesLevel };
256
204
  this.itemsShown.splice(this.ellipsesLevel, reverseCounter - this.ellipsesLevel, ellipsesItem);
257
205
  }
258
206
  // Manually detect changes to prevent them from not being detected on language change
259
207
  this.changeDetector.detectChanges();
260
208
  }
261
209
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SiBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
262
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SiBreadcrumbComponent, isStandalone: true, selector: "si-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, showRootAsText: { classPropertyName: "showRootAsText", publicName: "showRootAsText", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "documentClick($event.target)" } }, viewQueries: [{ propertyName: "breadcrumbElement", first: true, predicate: ["breadcrumb"], descendants: true, isSignal: true }, { propertyName: "breadcrumbElements", predicate: ["breadcrumbItem"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index; let isFirst = $first) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n @if (item.shortened) {\n <li #breadcrumbItem class=\"item text-nowrap shortened\">\n @if (!isFirst) {\n <si-icon class=\"d-block separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"\n toggleTemplate;\n context: { item: item, title: item.shortenedTitle }\n \"\n />\n @if (addExpandDropdown) {\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n </div>\n }\n </div>\n </li>\n } @else {\n <li #breadcrumbItem class=\"item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container *ngTemplateOutlet=\"toggleTemplate; context: { item: item, title: '' }\" />\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n @for (item of itemsHidden; track $index) {\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n }\n </div>\n </div>\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #toggleTemplate let-item=\"item\" let-title=\"title\" siBreadcrumbItemTemplate>\n <button\n type=\"button\"\n class=\"btn btn-link\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"controlId + item.level\"\n [attr.aria-expanded]=\"breadcrumbDropdownOpen === item.level\"\n (click)=\"toggleBreadcrumbDropdown(item.level)\"\n >{{ title }}...</button\n >\n</ng-template>\n\n<ng-template #dropdownTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"dropdown-item breadcrumb-link focus-inside\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n role=\"menuitem\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-disabled]=\"!item.link && !item.action && !item.href\"\n >{{ item.title }}</a\n >\n</ng-template>\n", styles: [".breadcrumb{flex-wrap:nowrap}.item{display:flex;align-items:center}.separator{color:var(--si-sys-color-text-secondary);margin-block:0;margin-inline:0}.disable-router-link,.disable-router-link:hover{pointer-events:none;color:var(--si-sys-color-text-disabled)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "directive", type: SiLinkDirective, selector: "[siLink]", inputs: ["siLink", "siLinkDefaultTarget", "actionParam", "activeClass", "exactMatch", "ariaCurrent"], outputs: ["activeChange"], exportAs: ["siLink"] }, { kind: "directive", type: SiResizeObserverDirective, selector: "[siResizeObserver]", inputs: ["resizeThrottle", "emitInitial"], outputs: ["siResizeObserver"] }, { kind: "directive", type: SiBreadcrumbItemTemplateDirective, selector: "[siBreadcrumbItemTemplate]" }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
210
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SiBreadcrumbComponent, isStandalone: true, selector: "si-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, showRootAsText: { classPropertyName: "showRootAsText", publicName: "showRootAsText", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "breadcrumbElement", first: true, predicate: ["breadcrumb"], descendants: true, isSignal: true }, { propertyName: "breadcrumbElements", predicate: ["breadcrumbItem"], descendants: true, isSignal: true }, { propertyName: "breadcrumbMenu", first: true, predicate: CdkMenuTrigger, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n <li #breadcrumbItem class=\"item\" [class.current-item]=\"item.lastItem\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <button\n type=\"button\"\n class=\"btn btn-link\"\n [attr.aria-label]=\"hiddenItemsLabel | translate\"\n [cdkMenuTriggerFor]=\"hiddenItemsTemplate\"\n >...</button\n >\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n siTooltipOverflow\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #hiddenItemsTemplate>\n <si-menu [attr.aria-label]=\"hiddenItemsLabel | translate\">\n @for (item of itemsHidden; track $index) {\n <a\n si-menu-item\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [disabled]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n >\n {{ item.title }}\n </a>\n }\n </si-menu>\n</ng-template>\n", styles: [".breadcrumb{flex-wrap:nowrap}.item{display:flex;align-items:center;flex-shrink:0}.item:not(.current-item) .breadcrumb-link{max-inline-size:24ch}.separator{color:var(--si-sys-color-text-secondary);margin-block:0;margin-inline:0}.disable-router-link,.disable-router-link:hover{pointer-events:none;color:var(--si-sys-color-text-disabled)}\n"], dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData", "cdkMenuTriggerTransformOriginOn"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "directive", type: SiLinkDirective, selector: "[siLink]", inputs: ["siLink", "siLinkDefaultTarget", "actionParam", "activeClass", "exactMatch", "ariaCurrent"], outputs: ["activeChange"], exportAs: ["siLink"] }, { kind: "directive", type: SiMenuDirective, selector: "si-menu" }, { kind: "component", type: SiMenuItemComponent, selector: "si-menu-item, a[si-menu-item], button[si-menu-item]" }, { kind: "directive", type: SiResizeObserverDirective, selector: "[siResizeObserver]", inputs: ["resizeThrottle", "emitInitial"], outputs: ["siResizeObserver"] }, { kind: "directive", type: SiTooltipOverflowDirective, selector: "[siTooltipOverflow]" }, { kind: "directive", type: SiBreadcrumbItemTemplateDirective, selector: "[siBreadcrumbItemTemplate]" }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
263
211
  }
264
212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SiBreadcrumbComponent, decorators: [{
265
213
  type: Component,
266
214
  args: [{ selector: 'si-breadcrumb', imports: [
215
+ CdkMenuTrigger,
267
216
  NgTemplateOutlet,
268
217
  SiIconComponent,
269
218
  SiLinkDirective,
219
+ SiMenuDirective,
220
+ SiMenuItemComponent,
270
221
  SiResizeObserverDirective,
222
+ SiTooltipOverflowDirective,
271
223
  SiTranslatePipe,
272
224
  SiBreadcrumbItemTemplateDirective
273
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index; let isFirst = $first) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n @if (item.shortened) {\n <li #breadcrumbItem class=\"item text-nowrap shortened\">\n @if (!isFirst) {\n <si-icon class=\"d-block separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"\n toggleTemplate;\n context: { item: item, title: item.shortenedTitle }\n \"\n />\n @if (addExpandDropdown) {\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n </div>\n }\n </div>\n </li>\n } @else {\n <li #breadcrumbItem class=\"item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container *ngTemplateOutlet=\"toggleTemplate; context: { item: item, title: '' }\" />\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n @for (item of itemsHidden; track $index) {\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n }\n </div>\n </div>\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #toggleTemplate let-item=\"item\" let-title=\"title\" siBreadcrumbItemTemplate>\n <button\n type=\"button\"\n class=\"btn btn-link\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"controlId + item.level\"\n [attr.aria-expanded]=\"breadcrumbDropdownOpen === item.level\"\n (click)=\"toggleBreadcrumbDropdown(item.level)\"\n >{{ title }}...</button\n >\n</ng-template>\n\n<ng-template #dropdownTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"dropdown-item breadcrumb-link focus-inside\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n role=\"menuitem\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-disabled]=\"!item.link && !item.action && !item.href\"\n >{{ item.title }}</a\n >\n</ng-template>\n", styles: [".breadcrumb{flex-wrap:nowrap}.item{display:flex;align-items:center}.separator{color:var(--si-sys-color-text-secondary);margin-block:0;margin-inline:0}.disable-router-link,.disable-router-link:hover{pointer-events:none;color:var(--si-sys-color-text-disabled)}\n"] }]
274
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], showRootAsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRootAsText", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], breadcrumbElement: [{ type: i0.ViewChild, args: ['breadcrumb', { isSignal: true }] }], breadcrumbElements: [{ type: i0.ViewChildren, args: ['breadcrumbItem', { isSignal: true }] }], documentClick: [{
275
- type: HostListener,
276
- args: ['document:click', ['$event.target']]
277
- }] } });
225
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n <li #breadcrumbItem class=\"item\" [class.current-item]=\"item.lastItem\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <button\n type=\"button\"\n class=\"btn btn-link\"\n [attr.aria-label]=\"hiddenItemsLabel | translate\"\n [cdkMenuTriggerFor]=\"hiddenItemsTemplate\"\n >...</button\n >\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n siTooltipOverflow\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #hiddenItemsTemplate>\n <si-menu [attr.aria-label]=\"hiddenItemsLabel | translate\">\n @for (item of itemsHidden; track $index) {\n <a\n si-menu-item\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [disabled]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n >\n {{ item.title }}\n </a>\n }\n </si-menu>\n</ng-template>\n", styles: [".breadcrumb{flex-wrap:nowrap}.item{display:flex;align-items:center;flex-shrink:0}.item:not(.current-item) .breadcrumb-link{max-inline-size:24ch}.separator{color:var(--si-sys-color-text-secondary);margin-block:0;margin-inline:0}.disable-router-link,.disable-router-link:hover{pointer-events:none;color:var(--si-sys-color-text-disabled)}\n"] }]
226
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], showRootAsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRootAsText", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], breadcrumbElement: [{ type: i0.ViewChild, args: ['breadcrumb', { isSignal: true }] }], breadcrumbElements: [{ type: i0.ViewChildren, args: ['breadcrumbItem', { isSignal: true }] }], breadcrumbMenu: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkMenuTrigger), { isSignal: true }] }] } });
278
227
 
279
228
  /**
280
229
  * Copyright (c) Siemens 2016 - 2026
@@ -1 +1 @@
1
- {"version":3,"file":"siemens-element-ng-breadcrumb.mjs","sources":["../../../../projects/element-ng/breadcrumb/si-breadcrumb-item-template.directive.ts","../../../../projects/element-ng/breadcrumb/si-breadcrumb.component.ts","../../../../projects/element-ng/breadcrumb/si-breadcrumb.component.html","../../../../projects/element-ng/breadcrumb/si-breadcrumb.module.ts","../../../../projects/element-ng/breadcrumb/index.ts","../../../../projects/element-ng/breadcrumb/siemens-element-ng-breadcrumb.ts"],"sourcesContent":["/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { Directive } from '@angular/core';\n\nimport { EnumeratedBreadcrumbItem } from './breadcrumb-item.model';\n\n@Directive({ selector: '[siBreadcrumbItemTemplate]' })\nexport class SiBreadcrumbItemTemplateDirective {\n static ngTemplateContextGuard(\n directive: SiBreadcrumbItemTemplateDirective,\n context: unknown\n ): context is { item: EnumeratedBreadcrumbItem; title?: string } {\n return true;\n }\n}\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n HostListener,\n inject,\n input,\n OnChanges,\n OnDestroy,\n viewChild,\n viewChildren\n} from '@angular/core';\nimport { elementBreadcrumbRoot, elementRight2 } from '@siemens/element-icons';\nimport { addIcons, SiIconComponent } from '@siemens/element-ng/icon';\nimport { SiLinkDirective } from '@siemens/element-ng/link';\nimport { SiResizeObserverDirective } from '@siemens/element-ng/resize-observer';\nimport {\n injectSiTranslateService,\n SiTranslatePipe,\n t\n} from '@siemens/element-translate-ng/translate';\nimport { merge, of, Subscription } from 'rxjs';\nimport { switchMap } from 'rxjs/operators';\n\nimport { BreadcrumbItem, EnumeratedBreadcrumbItem } from './breadcrumb-item.model';\nimport { SiBreadcrumbItemTemplateDirective } from './si-breadcrumb-item-template.directive';\n\n/**\n * Defines how many items should be displayed at the end of the breadcrumb if possible.\n */\nconst NUMBER_OF_SHOWN_ITEMS_AT_END = 2;\n\n/**\n * Defines how long a display item can be without it being shortened.\n * Cannot be lower than 4.\n * If this is 0, titles will not be shortened\n */\nconst ITEM_MAX_LENGTH = 30;\n\n/**\n * Defines how many characters of an item are always displayed in the beginning.\n * Must be at least 2 less than ITEM_MAX_LENGTH\n */\nconst ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING = 10;\n\n/**\n * Defines the width of the root icon in pixels.\n */\nconst ROOT_ICON_WIDTH = 24;\n\nlet controlIdCounter = 1;\n\n@Component({\n selector: 'si-breadcrumb',\n imports: [\n NgTemplateOutlet,\n SiIconComponent,\n SiLinkDirective,\n SiResizeObserverDirective,\n SiTranslatePipe,\n SiBreadcrumbItemTemplateDirective\n ],\n templateUrl: './si-breadcrumb.component.html',\n styleUrl: './si-breadcrumb.component.scss',\n changeDetection: ChangeDetectionStrategy.Eager\n})\nexport class SiBreadcrumbComponent implements OnChanges, OnDestroy {\n /** Array of breadcrumb items. */\n readonly items = input.required<BreadcrumbItem[]>();\n /**\n * Shows the \"root\" route as the provided title string instead of an icon.\n *\n * @defaultValue false\n */\n readonly showRootAsText = input(false, { transform: booleanAttribute });\n /**\n * Aria label for the main breadcrumb navigation. Needed for a11y.\n *\n * @defaultValue\n * ```\n * t(() => $localize`:@@SI_BREADCRUMB:Breadcrumb navigation`)\n * ```\n */\n readonly ariaLabel = input(t(() => $localize`:@@SI_BREADCRUMB:Breadcrumb navigation`));\n\n private translationSubscription?: Subscription;\n private itemsProcessed = false;\n private numberOfItems = 0;\n\n protected itemsShown: EnumeratedBreadcrumbItem[] = [];\n protected itemsHidden: EnumeratedBreadcrumbItem[] = [];\n protected breadcrumbShortened = false;\n protected ellipsesLevel = 0;\n // Record to allow for -1 (root).\n protected breadcrumbDropdownOpen: number | undefined = undefined;\n protected addExpandDropdown = false;\n protected controlId = `__si-breadcrumb-${controlIdCounter++}-`;\n protected readonly icons = addIcons({ elementBreadcrumbRoot, elementRight2 });\n\n private readonly breadcrumbElement = viewChild.required<ElementRef>('breadcrumb');\n private readonly breadcrumbElements = viewChildren<ElementRef>('breadcrumbItem');\n\n private changeDetector = inject(ChangeDetectorRef);\n private translate = injectSiTranslateService();\n\n ngOnChanges(): void {\n // Reprocess items on every change and on init\n this.processItems();\n }\n\n ngOnDestroy(): void {\n this.translationSubscription?.unsubscribe();\n }\n\n private processItems(): void {\n this.numberOfItems = this.items().length;\n\n this.translationSubscription?.unsubscribe();\n if (this.numberOfItems) {\n this.translationSubscription = merge(this.translate.translationChange, of(undefined))\n .pipe(switchMap(() => this.translate.translateAsync(this.items().map(item => item.title))))\n .subscribe(translatedTitles => {\n // Add the level to the items and check if they need to be shortened.\n // If they need to be shortened, shorten them at a convenient place.\n // Set the lastItem tag to true for the last item\n let counter = -1;\n const enumeratedItems = this.items().map(item => {\n counter++;\n const title = translatedTitles[item.title];\n let shortened = false;\n let shortenedTitle = title;\n // If this is not the last item and the title too long, shorten the title\n if (counter !== this.numberOfItems - 1 && title && title.length > ITEM_MAX_LENGTH) {\n shortened = true;\n // This regex gets the last space, dash or underscore.\n const regexMatch = title\n .slice(ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING, ITEM_MAX_LENGTH - 2)\n .match(/^.*[- _](?=.*?$)/);\n if (regexMatch) {\n shortenedTitle = title.slice(\n 0,\n ITEM_CHARACTERS_ALWAYS_DISPLAYED_IN_BEGINNING + regexMatch[0].length - 1\n );\n } else {\n shortenedTitle = title.slice(0, ITEM_MAX_LENGTH - 3);\n }\n }\n\n // If the root element should be displayed as text, set level not to 0.\n // This is used to distinguish in the template between icon and text.\n const level = counter === 0 && this.showRootAsText() ? -1 : counter;\n\n return {\n ...item,\n title,\n level,\n hide: false,\n shortened,\n shortenedTitle,\n lastItem: counter === this.numberOfItems - 1\n };\n });\n this.itemsShown = enumeratedItems;\n this.itemsHidden = [];\n this.breadcrumbShortened = false;\n this.breadcrumbDropdownOpen = undefined;\n this.itemsProcessed = true;\n this.resetBreadcrumb();\n });\n } else {\n this.itemsShown = [];\n this.itemsHidden = [];\n this.breadcrumbShortened = false;\n this.breadcrumbDropdownOpen = undefined;\n this.itemsProcessed = true;\n this.resetBreadcrumb();\n }\n }\n\n /*\n * Toggle dropdown (on click of ellipses), either for\n * the general dropdown list if itemLevel is at ellipsesLevel\n * or otherwise the name expansion at the specified item level.\n * Close any open dropdown before opening a new one.\n */\n protected toggleBreadcrumbDropdown(itemLevel: number): void {\n this.breadcrumbDropdownOpen = this.breadcrumbDropdownOpen === itemLevel ? undefined : itemLevel;\n }\n\n // Close dropdown on click anywhere else\n @HostListener('document:click', ['$event.target'])\n protected documentClick(targetElement: any): void {\n if (this.breadcrumbDropdownOpen) {\n if (!this.breadcrumbElement().nativeElement.contains(targetElement)) {\n // Close all dropdowns.\n this.breadcrumbDropdownOpen = undefined;\n }\n }\n }\n\n protected resetBreadcrumb(): void {\n if (this.itemsProcessed) {\n this.numberOfItems = this.items().length;\n // Add an additional the ellipses item to the end of the shownItems (breadcrumb items).\n // Disable addExpandDropdown for now, to make every item a proper SiBreadcrumbItemComponent.\n const ellipsesItem = { title: '...', level: this.numberOfItems, shortenedTitle: '' };\n this.itemsShown.push(ellipsesItem);\n if (this.breadcrumbShortened) {\n // If the breadcrumb was shortened before, remove the ellipses and add back itemsHidden (breadcrumb dropdown items).\n this.breadcrumbShortened = false;\n this.itemsShown.splice(this.ellipsesLevel, 1, ...this.itemsHidden);\n this.itemsHidden = [];\n }\n this.addExpandDropdown = false;\n // Wait for the next change detection cycle to measure the updated item length.\n this.changeDetector.detectChanges();\n this.calculateBreadcrumb();\n }\n }\n\n private calculateBreadcrumb(): void {\n this.addExpandDropdown = true;\n const maxWidth = this.breadcrumbElement().nativeElement.clientWidth;\n const breadcrumbElementsList = this.breadcrumbElements().map(item => item);\n // Measure the length of the last additional ellipses item, then remove it from itemsShown (breadcrumb items).\n const ellipsesWidth = breadcrumbElementsList[this.numberOfItems].nativeElement.offsetWidth;\n this.itemsShown.splice(this.numberOfItems, 1);\n let currentWidth = this.showRootAsText() ? 0 : ROOT_ICON_WIDTH;\n const numberOfItemsKeptAtEnd = Math.min(NUMBER_OF_SHOWN_ITEMS_AT_END, this.numberOfItems - 1);\n let reverseCounter = this.numberOfItems;\n // Test for numberOfItemsKeptAtEnd items from the end if they still fit, if not, set breadcrumbShortened to true.\n breadcrumbElementsList\n .slice(this.numberOfItems - numberOfItemsKeptAtEnd, this.numberOfItems)\n .reverse()\n .map(item => {\n if (!this.breadcrumbShortened) {\n const currentItemWidth = item.nativeElement.offsetWidth;\n if (currentWidth + currentItemWidth > maxWidth) {\n this.breadcrumbShortened = true;\n // Test if the ellipses item still fits, if not remove last (actually next in original order) item as well.\n if (currentWidth + ellipsesWidth > maxWidth) {\n reverseCounter++;\n }\n } else {\n currentWidth += currentItemWidth;\n reverseCounter--;\n }\n }\n });\n\n const start = this.showRootAsText() ? 0 : 1;\n let counter = start;\n // If breadcrumbShortened is not true yet, test for the rest of the items from the start\n // Whether they still fit, if not, set breadcrumbShortened to true.\n breadcrumbElementsList.slice(start, this.numberOfItems - numberOfItemsKeptAtEnd).map(item => {\n if (!this.breadcrumbShortened) {\n const currentItemWidth = item.nativeElement.offsetWidth;\n if (currentWidth + currentItemWidth > maxWidth) {\n this.breadcrumbShortened = true;\n // Test if the ellipses item still fits, if not remove last item as well.\n // If the counter is still on 1, instead remove last (actually next in original order) from\n // the previous reverse calculation\n if (currentWidth + ellipsesWidth > maxWidth) {\n if (counter > 1) {\n counter--;\n } else {\n reverseCounter++;\n }\n }\n } else {\n currentWidth += currentItemWidth;\n counter++;\n }\n }\n });\n // If breadcrumbShortened is true, move the items that do not fit to itemsHidden (breadcrumb dropdown items) and add ellipses item.\n if (this.breadcrumbShortened) {\n this.ellipsesLevel = counter;\n this.itemsHidden = this.itemsShown.slice(this.ellipsesLevel, reverseCounter);\n const ellipsesItem = { title: '...', level: this.ellipsesLevel, shortenedTitle: '' };\n this.itemsShown.splice(this.ellipsesLevel, reverseCounter - this.ellipsesLevel, ellipsesItem);\n }\n // Manually detect changes to prevent them from not being detected on language change\n this.changeDetector.detectChanges();\n }\n}\n","<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index; let isFirst = $first) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n @if (item.shortened) {\n <li #breadcrumbItem class=\"item text-nowrap shortened\">\n @if (!isFirst) {\n <si-icon class=\"d-block separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"\n toggleTemplate;\n context: { item: item, title: item.shortenedTitle }\n \"\n />\n @if (addExpandDropdown) {\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n </div>\n }\n </div>\n </li>\n } @else {\n <li #breadcrumbItem class=\"item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!isFirst) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <div class=\"breadcrumb-dropdown-wrapper\">\n <ng-container *ngTemplateOutlet=\"toggleTemplate; context: { item: item, title: '' }\" />\n <div\n class=\"dropdown-menu\"\n role=\"menu\"\n [id]=\"controlId + item.level\"\n [class.show]=\"breadcrumbDropdownOpen === item.level\"\n >\n @for (item of itemsHidden; track $index) {\n <ng-container *ngTemplateOutlet=\"dropdownTemplate; context: { item: item }\" />\n }\n </div>\n </div>\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #toggleTemplate let-item=\"item\" let-title=\"title\" siBreadcrumbItemTemplate>\n <button\n type=\"button\"\n class=\"btn btn-link\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"controlId + item.level\"\n [attr.aria-expanded]=\"breadcrumbDropdownOpen === item.level\"\n (click)=\"toggleBreadcrumbDropdown(item.level)\"\n >{{ title }}...</button\n >\n</ng-template>\n\n<ng-template #dropdownTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"dropdown-item breadcrumb-link focus-inside\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n role=\"menuitem\"\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-disabled]=\"!item.link && !item.action && !item.href\"\n >{{ item.title }}</a\n >\n</ng-template>\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { NgModule } from '@angular/core';\n\nimport { SiBreadcrumbComponent } from './si-breadcrumb.component';\n\n@NgModule({\n imports: [SiBreadcrumbComponent],\n exports: [SiBreadcrumbComponent]\n})\nexport class SiBreadcrumbModule {}\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nexport * from './breadcrumb-item.model';\nexport * from './si-breadcrumb.component';\nexport * from './si-breadcrumb.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"siemens-element-ng-breadcrumb.mjs","sources":["../../../../projects/element-ng/breadcrumb/si-breadcrumb-item-template.directive.ts","../../../../projects/element-ng/breadcrumb/si-breadcrumb.component.ts","../../../../projects/element-ng/breadcrumb/si-breadcrumb.component.html","../../../../projects/element-ng/breadcrumb/si-breadcrumb.module.ts","../../../../projects/element-ng/breadcrumb/index.ts","../../../../projects/element-ng/breadcrumb/siemens-element-ng-breadcrumb.ts"],"sourcesContent":["/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { Directive } from '@angular/core';\n\nimport { EnumeratedBreadcrumbItem } from './breadcrumb-item.model';\n\n@Directive({ selector: '[siBreadcrumbItemTemplate]' })\nexport class SiBreadcrumbItemTemplateDirective {\n static ngTemplateContextGuard(\n directive: SiBreadcrumbItemTemplateDirective,\n context: unknown\n ): context is { item: EnumeratedBreadcrumbItem; title?: string } {\n return true;\n }\n}\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { CdkMenuTrigger } from '@angular/cdk/menu';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n inject,\n input,\n OnChanges,\n OnDestroy,\n viewChild,\n viewChildren\n} from '@angular/core';\nimport { elementBreadcrumbRoot, elementRight2 } from '@siemens/element-icons';\nimport { addIcons, SiIconComponent } from '@siemens/element-ng/icon';\nimport { SiLinkDirective } from '@siemens/element-ng/link';\nimport { SiMenuDirective, SiMenuItemComponent } from '@siemens/element-ng/menu';\nimport { SiResizeObserverDirective } from '@siemens/element-ng/resize-observer';\nimport { SiTooltipOverflowDirective } from '@siemens/element-ng/tooltip';\nimport {\n injectSiTranslateService,\n SiTranslatePipe,\n t\n} from '@siemens/element-translate-ng/translate';\nimport { merge, of, Subscription } from 'rxjs';\nimport { switchMap } from 'rxjs/operators';\n\nimport { BreadcrumbItem, EnumeratedBreadcrumbItem } from './breadcrumb-item.model';\nimport { SiBreadcrumbItemTemplateDirective } from './si-breadcrumb-item-template.directive';\n\n/**\n * Defines how many items should be displayed at the end of the breadcrumb if possible.\n */\nconst NUMBER_OF_SHOWN_ITEMS_AT_END = 2;\n\n/**\n * Defines the width of the root icon in pixels.\n */\nconst ROOT_ICON_WIDTH = 24;\n\n@Component({\n selector: 'si-breadcrumb',\n imports: [\n CdkMenuTrigger,\n NgTemplateOutlet,\n SiIconComponent,\n SiLinkDirective,\n SiMenuDirective,\n SiMenuItemComponent,\n SiResizeObserverDirective,\n SiTooltipOverflowDirective,\n SiTranslatePipe,\n SiBreadcrumbItemTemplateDirective\n ],\n templateUrl: './si-breadcrumb.component.html',\n styleUrl: './si-breadcrumb.component.scss',\n changeDetection: ChangeDetectionStrategy.Eager\n})\nexport class SiBreadcrumbComponent implements OnChanges, OnDestroy {\n /** Array of breadcrumb items. */\n readonly items = input.required<BreadcrumbItem[]>();\n /**\n * Shows the \"root\" route as the provided title string instead of an icon.\n *\n * @defaultValue false\n */\n readonly showRootAsText = input(false, { transform: booleanAttribute });\n /**\n * Aria label for the main breadcrumb navigation. Needed for a11y.\n *\n * @defaultValue\n * ```\n * t(() => $localize`:@@SI_BREADCRUMB:Breadcrumb navigation`)\n * ```\n */\n readonly ariaLabel = input(t(() => $localize`:@@SI_BREADCRUMB:Breadcrumb navigation`));\n\n private translationSubscription?: Subscription;\n private itemsProcessed = false;\n private numberOfItems = 0;\n\n protected itemsShown: EnumeratedBreadcrumbItem[] = [];\n protected itemsHidden: EnumeratedBreadcrumbItem[] = [];\n protected breadcrumbShortened = false;\n protected ellipsesLevel = 0;\n protected readonly hiddenItemsLabel = t(\n () => $localize`:@@SI_BREADCRUMB.HIDDEN_ITEMS:Hidden breadcrumb items`\n );\n protected readonly icons = addIcons({ elementBreadcrumbRoot, elementRight2 });\n\n private readonly breadcrumbElement = viewChild.required<ElementRef>('breadcrumb');\n private readonly breadcrumbElements = viewChildren<ElementRef>('breadcrumbItem');\n private readonly breadcrumbMenu = viewChild(CdkMenuTrigger);\n\n private changeDetector = inject(ChangeDetectorRef);\n private translate = injectSiTranslateService();\n\n ngOnChanges(): void {\n // Reprocess items on every change and on init\n this.processItems();\n }\n\n ngOnDestroy(): void {\n this.translationSubscription?.unsubscribe();\n }\n\n private processItems(): void {\n this.numberOfItems = this.items().length;\n\n this.translationSubscription?.unsubscribe();\n if (this.numberOfItems) {\n this.translationSubscription = merge(this.translate.translationChange, of(undefined))\n .pipe(switchMap(() => this.translate.translateAsync(this.items().map(item => item.title))))\n .subscribe(translatedTitles => {\n // Add the level and mark the last item, keeping the full translated titles.\n let counter = -1;\n const enumeratedItems = this.items().map(item => {\n counter++;\n const title = translatedTitles[item.title];\n\n // If the root element should be displayed as text, set level not to 0.\n // This is used to distinguish in the template between icon and text.\n const level = counter === 0 && this.showRootAsText() ? -1 : counter;\n\n return {\n ...item,\n title,\n level,\n hide: false,\n lastItem: counter === this.numberOfItems - 1\n };\n });\n this.itemsShown = enumeratedItems;\n this.itemsHidden = [];\n this.breadcrumbShortened = false;\n this.itemsProcessed = true;\n this.resetBreadcrumb();\n });\n } else {\n this.itemsShown = [];\n this.itemsHidden = [];\n this.breadcrumbShortened = false;\n this.itemsProcessed = true;\n this.resetBreadcrumb();\n }\n }\n\n protected resetBreadcrumb(): void {\n this.breadcrumbMenu()?.close();\n if (this.itemsProcessed) {\n this.numberOfItems = this.items().length;\n // Add an additional the ellipses item to the end of the shownItems (breadcrumb items).\n const ellipsesItem = { title: '...', level: this.numberOfItems };\n this.itemsShown.push(ellipsesItem);\n if (this.breadcrumbShortened) {\n // If the breadcrumb was shortened before, remove the ellipses and add back itemsHidden (breadcrumb menu items).\n this.breadcrumbShortened = false;\n this.itemsShown.splice(this.ellipsesLevel, 1, ...this.itemsHidden);\n this.itemsHidden = [];\n }\n // Wait for the next change detection cycle to measure the updated item length.\n this.changeDetector.detectChanges();\n this.calculateBreadcrumb();\n }\n }\n\n private calculateBreadcrumb(): void {\n const maxWidth = this.breadcrumbElement().nativeElement.clientWidth;\n const breadcrumbElementsList = this.breadcrumbElements().map(item => item);\n // Measure the length of the last additional ellipses item, then remove it from itemsShown (breadcrumb items).\n const ellipsesWidth = breadcrumbElementsList[this.numberOfItems].nativeElement.offsetWidth;\n this.itemsShown.splice(this.numberOfItems, 1);\n let currentWidth = this.showRootAsText() ? 0 : ROOT_ICON_WIDTH;\n const numberOfItemsKeptAtEnd = Math.min(NUMBER_OF_SHOWN_ITEMS_AT_END, this.numberOfItems - 1);\n let reverseCounter = this.numberOfItems;\n // Test for numberOfItemsKeptAtEnd items from the end if they still fit, if not, set breadcrumbShortened to true.\n breadcrumbElementsList\n .slice(this.numberOfItems - numberOfItemsKeptAtEnd, this.numberOfItems)\n .reverse()\n .map(item => {\n if (!this.breadcrumbShortened) {\n const currentItemWidth = item.nativeElement.offsetWidth;\n if (currentWidth + currentItemWidth > maxWidth) {\n this.breadcrumbShortened = true;\n // Test if the ellipses item still fits, if not remove last (actually next in original order) item as well.\n if (currentWidth + ellipsesWidth > maxWidth) {\n reverseCounter++;\n }\n } else {\n currentWidth += currentItemWidth;\n reverseCounter--;\n }\n }\n });\n\n const start = this.showRootAsText() ? 0 : 1;\n let counter = start;\n // If breadcrumbShortened is not true yet, test for the rest of the items from the start\n // Whether they still fit, if not, set breadcrumbShortened to true.\n breadcrumbElementsList.slice(start, this.numberOfItems - numberOfItemsKeptAtEnd).map(item => {\n if (!this.breadcrumbShortened) {\n const currentItemWidth = item.nativeElement.offsetWidth;\n if (currentWidth + currentItemWidth > maxWidth) {\n this.breadcrumbShortened = true;\n // Test if the ellipses item still fits, if not remove last item as well.\n // If the counter is still on 1, instead remove last (actually next in original order) from\n // the previous reverse calculation\n if (currentWidth + ellipsesWidth > maxWidth) {\n if (counter > 1) {\n counter--;\n } else {\n reverseCounter++;\n }\n }\n } else {\n currentWidth += currentItemWidth;\n counter++;\n }\n }\n });\n // If breadcrumbShortened is true, move the items that do not fit to itemsHidden (breadcrumb menu items) and add ellipses item.\n if (this.breadcrumbShortened) {\n this.ellipsesLevel = counter;\n this.itemsHidden = this.itemsShown.slice(this.ellipsesLevel, reverseCounter);\n const ellipsesItem = { title: '...', level: this.ellipsesLevel };\n this.itemsShown.splice(this.ellipsesLevel, reverseCounter - this.ellipsesLevel, ellipsesItem);\n }\n // Manually detect changes to prevent them from not being detected on language change\n this.changeDetector.detectChanges();\n }\n}\n","<nav class=\"py-2\" [attr.aria-label]=\"ariaLabel() | translate\">\n <ol #breadcrumb class=\"breadcrumb\" (siResizeObserver)=\"resetBreadcrumb()\">\n @for (item of itemsShown; track $index) {\n @if (!breadcrumbShortened || item.level !== ellipsesLevel) {\n <li #breadcrumbItem class=\"item\" [class.current-item]=\"item.lastItem\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\" />\n </li>\n }\n @if (breadcrumbShortened && item.level === ellipsesLevel) {\n <li class=\"item breadcrumb-ellipses-item\">\n @if (!$first) {\n <si-icon class=\"d-block icon-sm separator flip-rtl\" [icon]=\"icons.elementRight2\" />\n }\n <button\n type=\"button\"\n class=\"btn btn-link\"\n [attr.aria-label]=\"hiddenItemsLabel | translate\"\n [cdkMenuTriggerFor]=\"hiddenItemsTemplate\"\n >...</button\n >\n </li>\n }\n }\n </ol>\n</nav>\n\n<ng-template #itemTemplate let-item=\"item\" siBreadcrumbItemTemplate>\n <a\n class=\"breadcrumb-link text-nowrap\"\n activeClass=\"active\"\n ariaCurrent=\"page\"\n siTooltipOverflow\n [class.disable-router-link]=\"!item.link && !item.action && !item.href\"\n [class.text-secondary]=\"item.lastItem\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n [attr.aria-label]=\"item.title\"\n [attr.aria-disabled]=\"!item.link && !item.href && !item.action\"\n >\n @if (item.level === 0) {\n <si-icon class=\"d-block icon-sm flip-rtl\" [icon]=\"icons.elementBreadcrumbRoot\" />\n } @else {\n <span>{{ item.title }}</span>\n }\n </a>\n</ng-template>\n\n<ng-template #hiddenItemsTemplate>\n <si-menu [attr.aria-label]=\"hiddenItemsLabel | translate\">\n @for (item of itemsHidden; track $index) {\n <a\n si-menu-item\n activeClass=\"active\"\n ariaCurrent=\"page\"\n [disabled]=\"!item.link && !item.action && !item.href\"\n [siLink]=\"item\"\n [exactMatch]=\"true\"\n >\n {{ item.title }}\n </a>\n }\n </si-menu>\n</ng-template>\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nimport { NgModule } from '@angular/core';\n\nimport { SiBreadcrumbComponent } from './si-breadcrumb.component';\n\n@NgModule({\n imports: [SiBreadcrumbComponent],\n exports: [SiBreadcrumbComponent]\n})\nexport class SiBreadcrumbModule {}\n","/**\n * Copyright (c) Siemens 2016 - 2026\n * SPDX-License-Identifier: MIT\n */\nexport * from './breadcrumb-item.model';\nexport * from './si-breadcrumb.component';\nexport * from './si-breadcrumb.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { inject, computed, ElementRef, signal, Directive, input, booleanAttribute, contentChildren, linkedSignal, DestroyRef, viewChild, ChangeDetectorRef, effect, Component } from '@angular/core';
3
3
  import { toSignal, toObservable } from '@angular/core/rxjs-interop';
4
4
  import { elementPause, elementPlay, elementRight2, elementLeft2 } from '@siemens/element-icons';
5
+ import { isRTL } from '@siemens/element-ng/common';
5
6
  import { addIcons, SiIconComponent } from '@siemens/element-ng/icon';
6
7
  import { SiResizeObserverDirective } from '@siemens/element-ng/resize-observer';
7
8
  import { t, injectSiTranslateService, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
@@ -441,8 +442,9 @@ class SiCarouselComponent {
441
442
  // Clamp the target to the scrollable range. A wrapped slide can be placed right at the track
442
443
  // edge, where the rect-derived target may exceed the maximum by a sub-pixel; without clamping
443
444
  // the loop would never reach it and never settle (leaving the order normalization undone).
444
- const maxScrollLeft = viewport.scrollWidth - viewport.clientWidth;
445
- const target = Math.max(0, Math.min(this.animationTargetLeft, maxScrollLeft));
445
+ const scrollRange = viewport.scrollWidth - viewport.clientWidth;
446
+ const [minScrollLeft, maxScrollLeft] = isRTL(viewport) ? [-scrollRange, 0] : [0, scrollRange];
447
+ const target = Math.max(minScrollLeft, Math.min(this.animationTargetLeft, maxScrollLeft));
446
448
  const diff = target - current;
447
449
  if (Math.abs(diff) < SCROLL_SETTLE_THRESHOLD) {
448
450
  viewport.scrollLeft = target;
@@ -541,7 +543,7 @@ class SiCarouselComponent {
541
543
  }
542
544
  }
543
545
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SiCarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
544
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SiCarouselComponent, isStandalone: true, selector: "si-carousel", inputs: { hidePageControls: { classPropertyName: "hidePageControls", publicName: "hidePageControls", isSignal: true, isRequired: false, transformFunction: null }, autoPlay: { classPropertyName: "autoPlay", publicName: "autoPlay", isSignal: true, isRequired: false, transformFunction: null }, ariaRole: { classPropertyName: "ariaRole", publicName: "ariaRole", isSignal: true, isRequired: false, transformFunction: null }, previousButtonAriaLabel: { classPropertyName: "previousButtonAriaLabel", publicName: "previousButtonAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, nextButtonAriaLabel: { classPropertyName: "nextButtonAriaLabel", publicName: "nextButtonAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, slidePageAriaLabel: { classPropertyName: "slidePageAriaLabel", publicName: "slidePageAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, playButtonLabel: { classPropertyName: "playButtonLabel", publicName: "playButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, pauseButtonLabel: { classPropertyName: "pauseButtonLabel", publicName: "pauseButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, carouselRoleDescription: { classPropertyName: "carouselRoleDescription", publicName: "carouselRoleDescription", isSignal: true, isRequired: false, transformFunction: null }, slideRoleDescription: { classPropertyName: "slideRoleDescription", publicName: "slideRoleDescription", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.role": "ariaRole()", "attr.aria-roledescription": "translatedCarouselRoleDescription()", "style.min-width.px": "pageControlContainerMinWidth()" } }, queries: [{ propertyName: "items", predicate: SiCarouselItemDirective, isSignal: true }], viewQueries: [{ propertyName: "viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "pageControl", first: true, predicate: ["pageControl"], descendants: true, isSignal: true }, { propertyName: "playPauseBtn", first: true, predicate: ["playPauseBtn"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"carousel-body d-flex flex-grow-1 align-items-center gap-2 min-h-0\">\n <div #viewport class=\"carousel-viewport flex-grow-1 align-self-stretch\" tabindex=\"0\">\n <div class=\"carousel-track h-100\">\n <ng-content />\n </div>\n </div>\n</div>\n@if ((!hidePageControls() || autoPlay()) && totalPages() > 1) {\n <div\n class=\"position-relative d-flex justify-content-center align-items-center mt-4\"\n (siResizeObserver)=\"onResize($event)\"\n >\n @if (!hidePageControls()) {\n <div #pageControl class=\"d-flex align-items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"previousButtonAriaLabel() | translate\"\n (click)=\"previous()\"\n >\n <si-icon [icon]=\"icons.elementLeft2\"\n /></button>\n <div class=\"d-flex align-items-center\">\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n <div\n class=\"d-flex overflow-hidden\"\n [style.width.px]=\"dotBtn.clientWidth * (totalPages() > 5 ? 5 : totalPages())\"\n >\n <div\n class=\"d-flex page-buttons\"\n [style.transform]=\"'translateX(-' + edgeLeftIndex() * dotBtn.clientWidth + 'px)'\"\n >\n @for (page of items(); track page) {\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost focus-inside btn-icon btn-sm d-flex align-items-center justify-content-center\"\n [aria-label]=\"\n slidePageAriaLabel() | translate: { page: $index + 1, total: totalPages() }\n \"\n [tabIndex]=\"$index >= edgeLeftIndex() && $index <= edgeRightIndex() ? 0 : -1\"\n [aria-current]=\"currentPage() === $index ? 'true' : 'false'\"\n (click)=\"goToSlide($index)\"\n ><span\n class=\"carousel-pager-dot d-block\"\n [class.active]=\"currentPage() === $index\"\n [class.rounded-circle]=\"currentPage() !== $index\"\n ></span\n ></button>\n }\n </div>\n </div>\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"nextButtonAriaLabel() | translate\"\n (click)=\"next()\"\n >\n <si-icon [icon]=\"icons.elementRight2\"\n /></button>\n </div>\n }\n\n @if (autoPlay()) {\n <div\n #playPauseBtn\n class=\"position-absolute top-0 end-0\"\n [class.invisible]=\"insufficientSpace()\"\n >\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon class=\"icon\" [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n <span aria-hidden=\"true\">{{\n (isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\n }}</span>\n </button>\n </div>\n @if (insufficientSpace()) {\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0 align-items-center position-absolute top-0 end-0 ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{--si-carousel-gap: var(--si-sys-sizing-spacing-y-60);display:flex;flex-direction:column;flex:1 1 0}.carousel-viewport{min-block-size:0;overflow-y:hidden;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}.page-buttons{transition:transform calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-track{display:flex;gap:var(--si-carousel-gap)}.carousel-pager-dot{inline-size:.375rem;block-size:.375rem;background-color:var(--si-sys-color-text-secondary);transition:background-color calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-pager-dot.active{transition:inline-size calc(.5s * var(--element-animations-enabled, 1)) ease,background-color calc(.5s * var(--element-animations-enabled, 1)) ease;inline-size:.75rem;background-color:var(--si-sys-color-background-accent);border-radius:6.25rem}.carousel-pager-small-dot{background-color:var(--si-sys-color-text-secondary);inline-size:.25rem;block-size:.25rem}\n"], dependencies: [{ kind: "directive", type: SiResizeObserverDirective, selector: "[siResizeObserver]", inputs: ["resizeThrottle", "emitInitial"], outputs: ["siResizeObserver"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
546
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SiCarouselComponent, isStandalone: true, selector: "si-carousel", inputs: { hidePageControls: { classPropertyName: "hidePageControls", publicName: "hidePageControls", isSignal: true, isRequired: false, transformFunction: null }, autoPlay: { classPropertyName: "autoPlay", publicName: "autoPlay", isSignal: true, isRequired: false, transformFunction: null }, ariaRole: { classPropertyName: "ariaRole", publicName: "ariaRole", isSignal: true, isRequired: false, transformFunction: null }, previousButtonAriaLabel: { classPropertyName: "previousButtonAriaLabel", publicName: "previousButtonAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, nextButtonAriaLabel: { classPropertyName: "nextButtonAriaLabel", publicName: "nextButtonAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, slidePageAriaLabel: { classPropertyName: "slidePageAriaLabel", publicName: "slidePageAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, playButtonLabel: { classPropertyName: "playButtonLabel", publicName: "playButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, pauseButtonLabel: { classPropertyName: "pauseButtonLabel", publicName: "pauseButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, carouselRoleDescription: { classPropertyName: "carouselRoleDescription", publicName: "carouselRoleDescription", isSignal: true, isRequired: false, transformFunction: null }, slideRoleDescription: { classPropertyName: "slideRoleDescription", publicName: "slideRoleDescription", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.role": "ariaRole()", "attr.aria-roledescription": "translatedCarouselRoleDescription()", "style.min-width.px": "pageControlContainerMinWidth()" } }, queries: [{ propertyName: "items", predicate: SiCarouselItemDirective, isSignal: true }], viewQueries: [{ propertyName: "viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "pageControl", first: true, predicate: ["pageControl"], descendants: true, isSignal: true }, { propertyName: "playPauseBtn", first: true, predicate: ["playPauseBtn"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"carousel-body d-flex flex-grow-1 align-items-center gap-2 min-h-0\">\n <div #viewport class=\"carousel-viewport flex-grow-1 align-self-stretch\" tabindex=\"0\">\n <div class=\"carousel-track h-100\">\n <ng-content />\n </div>\n </div>\n</div>\n@if ((!hidePageControls() || autoPlay()) && totalPages() > 1) {\n <div\n class=\"position-relative d-flex justify-content-center align-items-center mt-4\"\n (siResizeObserver)=\"onResize($event)\"\n >\n @if (!hidePageControls()) {\n <div #pageControl class=\"d-flex align-items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"previousButtonAriaLabel() | translate\"\n (click)=\"previous()\"\n >\n <si-icon class=\"flip-rtl\" [icon]=\"icons.elementLeft2\"\n /></button>\n <div class=\"d-flex align-items-center\">\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n <div\n class=\"d-flex overflow-hidden\"\n [style.width.px]=\"dotBtn.clientWidth * (totalPages() > 5 ? 5 : totalPages())\"\n >\n <div\n class=\"d-flex page-buttons\"\n [style.margin-inline-start.px]=\"-edgeLeftIndex() * dotBtn.clientWidth\"\n >\n @for (page of items(); track page) {\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost focus-inside btn-icon btn-sm d-flex align-items-center justify-content-center\"\n [aria-label]=\"\n slidePageAriaLabel() | translate: { page: $index + 1, total: totalPages() }\n \"\n [tabIndex]=\"$index >= edgeLeftIndex() && $index <= edgeRightIndex() ? 0 : -1\"\n [aria-current]=\"currentPage() === $index ? 'true' : 'false'\"\n (click)=\"goToSlide($index)\"\n ><span\n class=\"carousel-pager-dot d-block\"\n [class.active]=\"currentPage() === $index\"\n [class.rounded-circle]=\"currentPage() !== $index\"\n ></span\n ></button>\n }\n </div>\n </div>\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"nextButtonAriaLabel() | translate\"\n (click)=\"next()\"\n >\n <si-icon class=\"flip-rtl\" [icon]=\"icons.elementRight2\"\n /></button>\n </div>\n }\n\n @if (autoPlay()) {\n <div\n #playPauseBtn\n class=\"position-absolute top-0 end-0\"\n [class.invisible]=\"insufficientSpace()\"\n >\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon class=\"icon\" [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n <span aria-hidden=\"true\">{{\n (isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\n }}</span>\n </button>\n </div>\n @if (insufficientSpace()) {\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0 align-items-center position-absolute top-0 end-0 ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{--si-carousel-gap: var(--si-sys-sizing-spacing-y-60);display:flex;flex-direction:column;flex:1 1 0}.carousel-viewport{min-block-size:0;overflow-y:hidden;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}.page-buttons{transition:margin-inline-start calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-track{display:flex;gap:var(--si-carousel-gap)}.carousel-pager-dot{inline-size:.375rem;block-size:.375rem;background-color:var(--si-sys-color-text-secondary);transition:background-color calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-pager-dot.active{transition:inline-size calc(.5s * var(--element-animations-enabled, 1)) ease,background-color calc(.5s * var(--element-animations-enabled, 1)) ease;inline-size:.75rem;background-color:var(--si-sys-color-background-accent);border-radius:6.25rem}.carousel-pager-small-dot{background-color:var(--si-sys-color-text-secondary);inline-size:.25rem;block-size:.25rem}\n"], dependencies: [{ kind: "directive", type: SiResizeObserverDirective, selector: "[siResizeObserver]", inputs: ["resizeThrottle", "emitInitial"], outputs: ["siResizeObserver"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
545
547
  }
546
548
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SiCarouselComponent, decorators: [{
547
549
  type: Component,
@@ -549,7 +551,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
549
551
  '[attr.role]': 'ariaRole()',
550
552
  '[attr.aria-roledescription]': 'translatedCarouselRoleDescription()',
551
553
  '[style.min-width.px]': 'pageControlContainerMinWidth()'
552
- }, template: "<div class=\"carousel-body d-flex flex-grow-1 align-items-center gap-2 min-h-0\">\n <div #viewport class=\"carousel-viewport flex-grow-1 align-self-stretch\" tabindex=\"0\">\n <div class=\"carousel-track h-100\">\n <ng-content />\n </div>\n </div>\n</div>\n@if ((!hidePageControls() || autoPlay()) && totalPages() > 1) {\n <div\n class=\"position-relative d-flex justify-content-center align-items-center mt-4\"\n (siResizeObserver)=\"onResize($event)\"\n >\n @if (!hidePageControls()) {\n <div #pageControl class=\"d-flex align-items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"previousButtonAriaLabel() | translate\"\n (click)=\"previous()\"\n >\n <si-icon [icon]=\"icons.elementLeft2\"\n /></button>\n <div class=\"d-flex align-items-center\">\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n <div\n class=\"d-flex overflow-hidden\"\n [style.width.px]=\"dotBtn.clientWidth * (totalPages() > 5 ? 5 : totalPages())\"\n >\n <div\n class=\"d-flex page-buttons\"\n [style.transform]=\"'translateX(-' + edgeLeftIndex() * dotBtn.clientWidth + 'px)'\"\n >\n @for (page of items(); track page) {\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost focus-inside btn-icon btn-sm d-flex align-items-center justify-content-center\"\n [aria-label]=\"\n slidePageAriaLabel() | translate: { page: $index + 1, total: totalPages() }\n \"\n [tabIndex]=\"$index >= edgeLeftIndex() && $index <= edgeRightIndex() ? 0 : -1\"\n [aria-current]=\"currentPage() === $index ? 'true' : 'false'\"\n (click)=\"goToSlide($index)\"\n ><span\n class=\"carousel-pager-dot d-block\"\n [class.active]=\"currentPage() === $index\"\n [class.rounded-circle]=\"currentPage() !== $index\"\n ></span\n ></button>\n }\n </div>\n </div>\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"nextButtonAriaLabel() | translate\"\n (click)=\"next()\"\n >\n <si-icon [icon]=\"icons.elementRight2\"\n /></button>\n </div>\n }\n\n @if (autoPlay()) {\n <div\n #playPauseBtn\n class=\"position-absolute top-0 end-0\"\n [class.invisible]=\"insufficientSpace()\"\n >\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon class=\"icon\" [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n <span aria-hidden=\"true\">{{\n (isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\n }}</span>\n </button>\n </div>\n @if (insufficientSpace()) {\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0 align-items-center position-absolute top-0 end-0 ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{--si-carousel-gap: var(--si-sys-sizing-spacing-y-60);display:flex;flex-direction:column;flex:1 1 0}.carousel-viewport{min-block-size:0;overflow-y:hidden;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}.page-buttons{transition:transform calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-track{display:flex;gap:var(--si-carousel-gap)}.carousel-pager-dot{inline-size:.375rem;block-size:.375rem;background-color:var(--si-sys-color-text-secondary);transition:background-color calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-pager-dot.active{transition:inline-size calc(.5s * var(--element-animations-enabled, 1)) ease,background-color calc(.5s * var(--element-animations-enabled, 1)) ease;inline-size:.75rem;background-color:var(--si-sys-color-background-accent);border-radius:6.25rem}.carousel-pager-small-dot{background-color:var(--si-sys-color-text-secondary);inline-size:.25rem;block-size:.25rem}\n"] }]
554
+ }, template: "<div class=\"carousel-body d-flex flex-grow-1 align-items-center gap-2 min-h-0\">\n <div #viewport class=\"carousel-viewport flex-grow-1 align-self-stretch\" tabindex=\"0\">\n <div class=\"carousel-track h-100\">\n <ng-content />\n </div>\n </div>\n</div>\n@if ((!hidePageControls() || autoPlay()) && totalPages() > 1) {\n <div\n class=\"position-relative d-flex justify-content-center align-items-center mt-4\"\n (siResizeObserver)=\"onResize($event)\"\n >\n @if (!hidePageControls()) {\n <div #pageControl class=\"d-flex align-items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"previousButtonAriaLabel() | translate\"\n (click)=\"previous()\"\n >\n <si-icon class=\"flip-rtl\" [icon]=\"icons.elementLeft2\"\n /></button>\n <div class=\"d-flex align-items-center\">\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n <div\n class=\"d-flex overflow-hidden\"\n [style.width.px]=\"dotBtn.clientWidth * (totalPages() > 5 ? 5 : totalPages())\"\n >\n <div\n class=\"d-flex page-buttons\"\n [style.margin-inline-start.px]=\"-edgeLeftIndex() * dotBtn.clientWidth\"\n >\n @for (page of items(); track page) {\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost focus-inside btn-icon btn-sm d-flex align-items-center justify-content-center\"\n [aria-label]=\"\n slidePageAriaLabel() | translate: { page: $index + 1, total: totalPages() }\n \"\n [tabIndex]=\"$index >= edgeLeftIndex() && $index <= edgeRightIndex() ? 0 : -1\"\n [aria-current]=\"currentPage() === $index ? 'true' : 'false'\"\n (click)=\"goToSlide($index)\"\n ><span\n class=\"carousel-pager-dot d-block\"\n [class.active]=\"currentPage() === $index\"\n [class.rounded-circle]=\"currentPage() !== $index\"\n ></span\n ></button>\n }\n </div>\n </div>\n <div\n #dotBtn\n class=\"btn btn-tertiary-ghost btn-icon btn-sm pe-none\"\n [class.opacity-0]=\"totalPages() <= 5\"\n [class.position-absolute]=\"totalPages() <= 5\"\n >\n <span class=\"carousel-pager-small-dot d-block rounded-circle\"></span>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0\"\n [aria-label]=\"nextButtonAriaLabel() | translate\"\n (click)=\"next()\"\n >\n <si-icon class=\"flip-rtl\" [icon]=\"icons.elementRight2\"\n /></button>\n </div>\n }\n\n @if (autoPlay()) {\n <div\n #playPauseBtn\n class=\"position-absolute top-0 end-0\"\n [class.invisible]=\"insufficientSpace()\"\n >\n <button\n type=\"button\"\n class=\"btn btn-tertiary-ghost ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon class=\"icon\" [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n <span aria-hidden=\"true\">{{\n (isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\n }}</span>\n </button>\n </div>\n @if (insufficientSpace()) {\n <button\n type=\"button\"\n class=\"btn btn-icon btn-tertiary-ghost flex-shrink-0 align-items-center position-absolute top-0 end-0 ms-2\"\n [aria-label]=\"(isPaused() ? playButtonLabel() : pauseButtonLabel()) | translate\"\n (click)=\"toggleAutoPlay()\"\n >\n <si-icon [icon]=\"isPaused() ? icons.elementPlay : icons.elementPause\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{--si-carousel-gap: var(--si-sys-sizing-spacing-y-60);display:flex;flex-direction:column;flex:1 1 0}.carousel-viewport{min-block-size:0;overflow-y:hidden;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}.page-buttons{transition:margin-inline-start calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-track{display:flex;gap:var(--si-carousel-gap)}.carousel-pager-dot{inline-size:.375rem;block-size:.375rem;background-color:var(--si-sys-color-text-secondary);transition:background-color calc(.5s * var(--element-animations-enabled, 1)) ease}.carousel-pager-dot.active{transition:inline-size calc(.5s * var(--element-animations-enabled, 1)) ease,background-color calc(.5s * var(--element-animations-enabled, 1)) ease;inline-size:.75rem;background-color:var(--si-sys-color-background-accent);border-radius:6.25rem}.carousel-pager-small-dot{background-color:var(--si-sys-color-text-secondary);inline-size:.25rem;block-size:.25rem}\n"] }]
553
555
  }], ctorParameters: () => [], propDecorators: { hidePageControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidePageControls", required: false }] }], autoPlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoPlay", required: false }] }], ariaRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaRole", required: false }] }], previousButtonAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousButtonAriaLabel", required: false }] }], nextButtonAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextButtonAriaLabel", required: false }] }], slidePageAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "slidePageAriaLabel", required: false }] }], playButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "playButtonLabel", required: false }] }], pauseButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pauseButtonLabel", required: false }] }], carouselRoleDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "carouselRoleDescription", required: false }] }], slideRoleDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideRoleDescription", required: false }] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SiCarouselItemDirective), { isSignal: true }] }], viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], pageControl: [{ type: i0.ViewChild, args: ['pageControl', { isSignal: true }] }], playPauseBtn: [{ type: i0.ViewChild, args: ['playPauseBtn', { isSignal: true }] }] } });
554
556
 
555
557
  /**