@siemens/element-ng 48.0.0-next.2 → 48.0.0-next.3

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 (112) hide show
  1. package/card/index.d.ts +0 -1
  2. package/content-action-bar/index.d.ts +3 -4
  3. package/fesm2022/siemens-element-ng-about.mjs +4 -4
  4. package/fesm2022/siemens-element-ng-about.mjs.map +1 -1
  5. package/fesm2022/siemens-element-ng-accordion.mjs +4 -4
  6. package/fesm2022/siemens-element-ng-accordion.mjs.map +1 -1
  7. package/fesm2022/siemens-element-ng-action-modal.mjs +9 -9
  8. package/fesm2022/siemens-element-ng-action-modal.mjs.map +1 -1
  9. package/fesm2022/siemens-element-ng-application-header.mjs +29 -29
  10. package/fesm2022/siemens-element-ng-application-header.mjs.map +1 -1
  11. package/fesm2022/siemens-element-ng-avatar.mjs +4 -4
  12. package/fesm2022/siemens-element-ng-avatar.mjs.map +1 -1
  13. package/fesm2022/siemens-element-ng-badge.mjs +5 -5
  14. package/fesm2022/siemens-element-ng-badge.mjs.map +1 -1
  15. package/fesm2022/siemens-element-ng-breadcrumb-router.mjs +2 -2
  16. package/fesm2022/siemens-element-ng-breadcrumb-router.mjs.map +1 -1
  17. package/fesm2022/siemens-element-ng-breadcrumb.mjs +4 -4
  18. package/fesm2022/siemens-element-ng-breadcrumb.mjs.map +1 -1
  19. package/fesm2022/siemens-element-ng-card.mjs +0 -1
  20. package/fesm2022/siemens-element-ng-card.mjs.map +1 -1
  21. package/fesm2022/siemens-element-ng-circle-status.mjs +3 -3
  22. package/fesm2022/siemens-element-ng-circle-status.mjs.map +1 -1
  23. package/fesm2022/siemens-element-ng-color-picker.mjs +4 -4
  24. package/fesm2022/siemens-element-ng-color-picker.mjs.map +1 -1
  25. package/fesm2022/siemens-element-ng-column-selection-dialog.mjs +7 -7
  26. package/fesm2022/siemens-element-ng-column-selection-dialog.mjs.map +1 -1
  27. package/fesm2022/siemens-element-ng-content-action-bar.mjs +9 -14
  28. package/fesm2022/siemens-element-ng-content-action-bar.mjs.map +1 -1
  29. package/fesm2022/siemens-element-ng-dashboard.mjs +14 -14
  30. package/fesm2022/siemens-element-ng-dashboard.mjs.map +1 -1
  31. package/fesm2022/siemens-element-ng-date-range-filter.mjs +4 -4
  32. package/fesm2022/siemens-element-ng-date-range-filter.mjs.map +1 -1
  33. package/fesm2022/siemens-element-ng-datepicker.mjs +12 -12
  34. package/fesm2022/siemens-element-ng-datepicker.mjs.map +1 -1
  35. package/fesm2022/siemens-element-ng-electron-titlebar.mjs +3 -3
  36. package/fesm2022/siemens-element-ng-electron-titlebar.mjs.map +1 -1
  37. package/fesm2022/siemens-element-ng-empty-state.mjs +3 -3
  38. package/fesm2022/siemens-element-ng-empty-state.mjs.map +1 -1
  39. package/fesm2022/siemens-element-ng-file-uploader.mjs +6 -6
  40. package/fesm2022/siemens-element-ng-file-uploader.mjs.map +1 -1
  41. package/fesm2022/siemens-element-ng-filtered-search.mjs +7 -7
  42. package/fesm2022/siemens-element-ng-filtered-search.mjs.map +1 -1
  43. package/fesm2022/siemens-element-ng-formly.mjs +5 -5
  44. package/fesm2022/siemens-element-ng-formly.mjs.map +1 -1
  45. package/fesm2022/siemens-element-ng-help-button.mjs +6 -6
  46. package/fesm2022/siemens-element-ng-help-button.mjs.map +1 -1
  47. package/fesm2022/siemens-element-ng-icon-status.mjs +3 -3
  48. package/fesm2022/siemens-element-ng-icon-status.mjs.map +1 -1
  49. package/fesm2022/siemens-element-ng-icon.mjs +207 -171
  50. package/fesm2022/siemens-element-ng-icon.mjs.map +1 -1
  51. package/fesm2022/siemens-element-ng-info-page.mjs +3 -3
  52. package/fesm2022/siemens-element-ng-info-page.mjs.map +1 -1
  53. package/fesm2022/siemens-element-ng-menu.mjs +10 -10
  54. package/fesm2022/siemens-element-ng-menu.mjs.map +1 -1
  55. package/fesm2022/siemens-element-ng-number-input.mjs +4 -4
  56. package/fesm2022/siemens-element-ng-number-input.mjs.map +1 -1
  57. package/fesm2022/siemens-element-ng-pagination.mjs +3 -3
  58. package/fesm2022/siemens-element-ng-pagination.mjs.map +1 -1
  59. package/fesm2022/siemens-element-ng-password-toggle.mjs +4 -4
  60. package/fesm2022/siemens-element-ng-password-toggle.mjs.map +1 -1
  61. package/fesm2022/siemens-element-ng-phone-number.mjs +4 -4
  62. package/fesm2022/siemens-element-ng-phone-number.mjs.map +1 -1
  63. package/fesm2022/siemens-element-ng-photo-upload.mjs +4 -4
  64. package/fesm2022/siemens-element-ng-photo-upload.mjs.map +1 -1
  65. package/fesm2022/siemens-element-ng-pills-input.mjs +4 -4
  66. package/fesm2022/siemens-element-ng-pills-input.mjs.map +1 -1
  67. package/fesm2022/siemens-element-ng-popover-next.mjs +4 -4
  68. package/fesm2022/siemens-element-ng-popover-next.mjs.map +1 -1
  69. package/fesm2022/siemens-element-ng-popover.mjs +3 -3
  70. package/fesm2022/siemens-element-ng-popover.mjs.map +1 -1
  71. package/fesm2022/siemens-element-ng-result-details-list.mjs +3 -3
  72. package/fesm2022/siemens-element-ng-result-details-list.mjs.map +1 -1
  73. package/fesm2022/siemens-element-ng-search-bar.mjs +4 -4
  74. package/fesm2022/siemens-element-ng-search-bar.mjs.map +1 -1
  75. package/fesm2022/siemens-element-ng-select.mjs +13 -18
  76. package/fesm2022/siemens-element-ng-select.mjs.map +1 -1
  77. package/fesm2022/siemens-element-ng-side-panel.mjs +4 -4
  78. package/fesm2022/siemens-element-ng-side-panel.mjs.map +1 -1
  79. package/fesm2022/siemens-element-ng-slider.mjs +4 -4
  80. package/fesm2022/siemens-element-ng-slider.mjs.map +1 -1
  81. package/fesm2022/siemens-element-ng-sort-bar.mjs +3 -3
  82. package/fesm2022/siemens-element-ng-sort-bar.mjs.map +1 -1
  83. package/fesm2022/siemens-element-ng-split.mjs +4 -4
  84. package/fesm2022/siemens-element-ng-split.mjs.map +1 -1
  85. package/fesm2022/siemens-element-ng-status-bar.mjs +7 -7
  86. package/fesm2022/siemens-element-ng-status-bar.mjs.map +1 -1
  87. package/fesm2022/siemens-element-ng-status-toggle.mjs +4 -4
  88. package/fesm2022/siemens-element-ng-status-toggle.mjs.map +1 -1
  89. package/fesm2022/siemens-element-ng-summary-chip.mjs +3 -3
  90. package/fesm2022/siemens-element-ng-summary-chip.mjs.map +1 -1
  91. package/fesm2022/siemens-element-ng-summary-widget.mjs +3 -3
  92. package/fesm2022/siemens-element-ng-summary-widget.mjs.map +1 -1
  93. package/fesm2022/siemens-element-ng-tabs-next.mjs +7 -7
  94. package/fesm2022/siemens-element-ng-tabs-next.mjs.map +1 -1
  95. package/fesm2022/siemens-element-ng-tabs.mjs +3 -3
  96. package/fesm2022/siemens-element-ng-tabs.mjs.map +1 -1
  97. package/fesm2022/siemens-element-ng-threshold.mjs +10 -18
  98. package/fesm2022/siemens-element-ng-threshold.mjs.map +1 -1
  99. package/fesm2022/siemens-element-ng-toast-notification.mjs +5 -9
  100. package/fesm2022/siemens-element-ng-toast-notification.mjs.map +1 -1
  101. package/fesm2022/siemens-element-ng-tour.mjs +4 -4
  102. package/fesm2022/siemens-element-ng-tour.mjs.map +1 -1
  103. package/fesm2022/siemens-element-ng-translate.mjs.map +1 -1
  104. package/fesm2022/siemens-element-ng-typeahead.mjs +4 -4
  105. package/fesm2022/siemens-element-ng-typeahead.mjs.map +1 -1
  106. package/fesm2022/siemens-element-ng-unauthorized-page.mjs +3 -3
  107. package/fesm2022/siemens-element-ng-unauthorized-page.mjs.map +1 -1
  108. package/fesm2022/siemens-element-ng-wizard.mjs +4 -10
  109. package/fesm2022/siemens-element-ng-wizard.mjs.map +1 -1
  110. package/formly/index.d.ts +1 -1
  111. package/icon/index.d.ts +108 -72
  112. package/package.json +7 -7
@@ -1,40 +1,168 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, ChangeDetectionStrategy, Component, NgModule, inject, DestroyRef, Injectable, InjectionToken } from '@angular/core';
2
+ import { inject, DestroyRef, Injectable, InjectionToken, input, computed, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
3
3
  import { NgClass } from '@angular/common';
4
- import { SiTranslatePipe, t } from '@siemens/element-translate-ng/translate';
5
4
  import { DomSanitizer } from '@angular/platform-browser';
6
5
  import { SiThemeService } from '@siemens/element-ng/theme';
6
+ import { t, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
7
7
 
8
8
  /**
9
9
  * Copyright (c) Siemens 2016 - 2025
10
10
  * SPDX-License-Identifier: MIT
11
11
  */
12
+ const parseDataSvgIcon = (icon, domSanitizer) => {
13
+ const parsed = /^data:image\/svg\+xml;utf8,(.*)$/.exec(icon);
14
+ if (!parsed) {
15
+ console.error('Failed to parse icon', icon);
16
+ return '';
17
+ }
18
+ return domSanitizer.bypassSecurityTrustHtml(parsed[1]);
19
+ };
20
+ const registeredIcons = new Map();
21
+ /**
22
+ * Adds the provided icons.
23
+ * It requires an Angular InjectionContent.
24
+ * The Icons are available until the component is destroyed.
25
+ * Call this function only in the component which actually uses the icon.
26
+ * Importing all icons on the global level is discouraged.
27
+ *
28
+ * When using a string instead of the object to use an icon,
29
+ * use the kebab-case version of the icon name.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { elementIcon } from '@simpl/element-icons/ionic';
34
+ * import { addIcons } from '@siemens/element-ng/icon'
35
+ *
36
+ * @Component({`<si-icon [icon]="icons.elementIcon"`})
37
+ * class MyComponent {
38
+ * icons = addIcons({ elementIcon })
39
+ * }
40
+ * ```
41
+ */
42
+ const addIcons = (icons) => {
43
+ const iconMap = {};
44
+ const domSanitizer = inject(DomSanitizer);
45
+ for (const [key, rawContent] of Object.entries(icons)) {
46
+ const registeredIcon = registeredIcons.get(key) ?? {
47
+ content: parseDataSvgIcon(rawContent, domSanitizer),
48
+ referenceCount: 0
49
+ };
50
+ registeredIcon.referenceCount++;
51
+ registeredIcons.set(key, registeredIcon);
52
+ iconMap[key] = key;
53
+ }
54
+ // Delete registered Icons after Component is destroyed to optimize memory usage.
55
+ // WeakMap must not be used, as the Icon can only be removed on component destruction.
56
+ // When using a WeakMap it would also get destroyed if it is not referenced, but the component may use it later again.
57
+ inject(DestroyRef).onDestroy(() => {
58
+ for (const key of Object.keys(icons)) {
59
+ const registeredIcon = registeredIcons.get(key);
60
+ if (registeredIcon.referenceCount === 1) {
61
+ registeredIcons.delete(key);
62
+ }
63
+ else {
64
+ registeredIcon.referenceCount--;
65
+ }
66
+ }
67
+ });
68
+ return iconMap;
69
+ };
70
+ const getIcon = (key) => registeredIcons.get(key)?.content;
71
+ class IconService {
72
+ themeService = inject(SiThemeService);
73
+ getIcon(name) {
74
+ const camelCaseName = this.kebabToCamelCase(name);
75
+ return this.themeService.themeIcons()[camelCaseName] ?? getIcon(camelCaseName);
76
+ }
77
+ kebabToCamelCase(str) {
78
+ return str.replace(/-./g, match => match.charAt(1).toUpperCase());
79
+ }
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
81
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, providedIn: 'root' });
82
+ }
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, decorators: [{
84
+ type: Injectable,
85
+ args: [{ providedIn: 'root' }]
86
+ }] });
87
+
88
+ /**
89
+ * Copyright (c) Siemens 2016 - 2025
90
+ * SPDX-License-Identifier: MIT
91
+ */
92
+ const ICON_CONFIG = new InjectionToken('ICON_CONFIG', {
93
+ providedIn: 'root',
94
+ factory: () => ({ disableSvgIcons: true })
95
+ });
96
+ /**
97
+ * Configure how Element handles icons. Provide only once in your global configuration.
98
+ *
99
+ * @experimental
100
+ */
101
+ const provideIconConfig = (config) => ({
102
+ provide: ICON_CONFIG,
103
+ useValue: config
104
+ });
105
+ /**
106
+ * Component to render a font or SVG icon depending on the configuration.
107
+ * If no SVG icon is found, the component will fall back to render the icon-font.
108
+ * In that case, an application must ensure that the icon font is loaded.
109
+ * This component will only attach the respective class.
110
+ *
111
+ * The content of this component is hidden in the a11y tree.
112
+ * If needed, the consumer must set proper labels.
113
+ *
114
+ * @experimental
115
+ */
12
116
  class SiIconComponent {
13
- /** Icon token, see {@link https://element.siemens.io/icons/element} */
14
- icon = input();
15
- /** Color class, see {@link https://element.siemens.io/fundamentals/typography/#color-variants-classes} */
16
- color = input();
17
- /** Icon token, see {@link https://element.siemens.io/fundamentals/icons/} */
18
- stackedIcon = input();
19
- /** Color class, see {@link https://element.siemens.io/fundamentals/icons/} */
20
- stackedColor = input();
21
- /** Alternative name or translation key for icon. Used for A11y. */
22
- alt = input();
23
117
  /**
24
- * Text-size class for icon size, see {@link https://element.siemens.io/fundamentals/typography/#type-styles-classes}
118
+ * Define which icon should be rendered.
119
+ * Provide using:
120
+ * - value of the icon map provided by `addIcons`
121
+ * - (not recommended): plain string in kebab-case or camelCase
25
122
  *
26
- * @defaultValue 'icon'
123
+ * @example
124
+ * ```ts
125
+ * import { elementUser } from '@simpl/element-icons/ionic';
126
+ *
127
+ * @Component({template: `
128
+ * <si-icon [icon]="icons.elementUser" />
129
+ * <si-icon icon="element-user" />
130
+ * <si-icon icon="elementUser" />
131
+ *
132
+ * `})
133
+ * class MyComponent {
134
+ * icons = addIcons(elementUser);
135
+ * }
136
+ * ```
27
137
  */
28
- size = input('icon');
29
- altText = computed(() => {
30
- return this.alt() ?? this.icon()?.replace('element-', '').split('-').join(' ') ?? '';
31
- });
138
+ icon = input.required();
139
+ config = inject(ICON_CONFIG);
140
+ iconService = inject(IconService);
141
+ svgIcon = computed(() => this.config.disableSvgIcons ? undefined : this.iconService.getIcon(this.icon()));
142
+ /** Icon class, which is ensured to be kebab-case. */
143
+ fontIcon = computed(() => this.svgIcon() ? undefined : this.camelToKebabCase(this.icon()));
144
+ camelToKebabCase(str) {
145
+ return str
146
+ .replace(/([a-z])([A-Z0-9])/g, '$1-$2')
147
+ .replace(/([0-9])([A-Z])/g, '$1-$2')
148
+ .toLowerCase();
149
+ }
32
150
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiIconComponent, isStandalone: true, selector: "si-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, stackedIcon: { classPropertyName: "stackedIcon", publicName: "stackedIcon", isSignal: true, isRequired: false, transformFunction: null }, stackedColor: { classPropertyName: "stackedColor", publicName: "stackedColor", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\n class=\"d-inline-block position-relative\"\n [attr.aria-label]=\"altText() ? (altText() | translate) : null\"\n [attr.aria-hidden]=\"!altText()\"\n [attr.role]=\"altText() ? 'img' : 'presentation'\"\n [ngClass]=\"[icon() ?? '', color() ?? '', size()]\"\n>\n @if (stackedIcon()) {\n <i\n class=\"position-absolute start-0\"\n aria-hidden=\"true\"\n [ngClass]=\"[stackedIcon(), stackedColor() ?? '']\"\n ></i>\n }\n</span>\n", styles: [":host,span{line-height:1}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
151
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: SiIconComponent, isStandalone: true, selector: "si-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-icon": "icon()" } }, ngImport: i0, template: ` <div
152
+ aria-hidden="true"
153
+ [ngClass]="svgIcon() ? '' : fontIcon()"
154
+ [innerHTML]="svgIcon()"
155
+ ></div>`, isInline: true, styles: [":host{display:inline-flex;font-weight:400;vertical-align:middle;line-height:1}:host ::ng-deep svg{display:block;block-size:1em;fill:currentColor}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
34
156
  }
35
157
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconComponent, decorators: [{
36
158
  type: Component,
37
- args: [{ selector: 'si-icon', imports: [NgClass, SiTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span\n class=\"d-inline-block position-relative\"\n [attr.aria-label]=\"altText() ? (altText() | translate) : null\"\n [attr.aria-hidden]=\"!altText()\"\n [attr.role]=\"altText() ? 'img' : 'presentation'\"\n [ngClass]=\"[icon() ?? '', color() ?? '', size()]\"\n>\n @if (stackedIcon()) {\n <i\n class=\"position-absolute start-0\"\n aria-hidden=\"true\"\n [ngClass]=\"[stackedIcon(), stackedColor() ?? '']\"\n ></i>\n }\n</span>\n", styles: [":host,span{line-height:1}\n"] }]
159
+ args: [{ selector: 'si-icon', imports: [NgClass], template: ` <div
160
+ aria-hidden="true"
161
+ [ngClass]="svgIcon() ? '' : fontIcon()"
162
+ [innerHTML]="svgIcon()"
163
+ ></div>`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
164
+ '[attr.data-icon]': 'icon()'
165
+ }, styles: [":host{display:inline-flex;font-weight:400;vertical-align:middle;line-height:1}:host ::ng-deep svg{display:block;block-size:1em;fill:currentColor}\n"] }]
38
166
  }] });
39
167
 
40
168
  /**
@@ -115,86 +243,6 @@ const elementAlarmTick = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/
115
243
  const elementUser = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path d='M256 252a76 76 0 1 0-76-76 76.08 76.08 0 0 0 76 76Zm0-128a52 52 0 1 1-52 52 52.06 52.06 0 0 1 52-52ZM124 360.14a12 12 0 0 0 6.71-2.06c.61-.41 61.54-41.08 126.14-41.08 75.3 0 122.86 39.84 123.3 40.23a12 12 0 0 0 15.68-18.18c-2.19-1.88-54.39-46.05-139-46.05C185 293 120 336.35 117.28 338.19a12 12 0 0 0 6.72 21.95Z'/></svg>";
116
244
  const elementHelp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path d='M256 64C150.13 64 64 150.13 64 256s86.13 192 192 192 192-86.13 192-192S361.87 64 256 64Zm0 360c-92.64 0-168-75.36-168-168S163.36 88 256 88s168 75.36 168 168-75.36 168-168 168Z'/><path d='M256 305a12 12 0 0 1-12-12v-29.22a12 12 0 0 1 6.51-10.67 11.63 11.63 0 0 1 1.67-.71c1.14-.4 38.54-14.05 38.54-36.4a36 36 0 0 0-70-12 12 12 0 1 1-22.64-8 60 60 0 0 1 116.6 20c0 31-31.39 48.92-46.72 55.84V293A12 12 0 0 1 256 305ZM256.11 360h-.22a16 16 0 0 1 0-32h.22a16 16 0 0 1 0 32Z'/></svg>";
117
245
 
118
- /**
119
- * Copyright (c) Siemens 2016 - 2025
120
- * SPDX-License-Identifier: MIT
121
- */
122
- const parseDataSvgIcon = (icon, domSanitizer) => {
123
- const parsed = /^data:image\/svg\+xml;utf8,(.*)$/.exec(icon);
124
- if (!parsed) {
125
- console.error('Failed to parse icon', icon);
126
- return '';
127
- }
128
- return domSanitizer.bypassSecurityTrustHtml(parsed[1]);
129
- };
130
- const registeredIcons = new Map();
131
- /**
132
- * Adds the provided icons.
133
- * It requires an Angular InjectionContent.
134
- * The Icons are available until the component is destroyed.
135
- * Call this function only in the component which actually uses the icon.
136
- * Importing all icons on the global level is discouraged.
137
- *
138
- * When using a string instead of the object to use an icon,
139
- * use the kebab-case version of the icon name.
140
- *
141
- * @example
142
- * ```ts
143
- * import { elementIcon } from '@simpl/element-icons/ionic';
144
- * import { addIcons } from '@siemens/element-ng/icon'
145
- *
146
- * @Component({`<si-icon-next [icon]="icons.elementIcon"`})
147
- * class MyComponent {
148
- * icons = addIcons({ elementIcon })
149
- * }
150
- * ```
151
- */
152
- const addIcons = (icons) => {
153
- const iconMap = {};
154
- const domSanitizer = inject(DomSanitizer);
155
- for (const [key, rawContent] of Object.entries(icons)) {
156
- const registeredIcon = registeredIcons.get(key) ?? {
157
- content: parseDataSvgIcon(rawContent, domSanitizer),
158
- referenceCount: 0
159
- };
160
- registeredIcon.referenceCount++;
161
- registeredIcons.set(key, registeredIcon);
162
- iconMap[key] = key;
163
- }
164
- // Delete registered Icons after Component is destroyed to optimize memory usage.
165
- // WeakMap must not be used, as the Icon can only be removed on component destruction.
166
- // When using a WeakMap it would also get destroyed if it is not referenced, but the component may use it later again.
167
- inject(DestroyRef).onDestroy(() => {
168
- for (const key of Object.keys(icons)) {
169
- const registeredIcon = registeredIcons.get(key);
170
- if (registeredIcon.referenceCount === 1) {
171
- registeredIcons.delete(key);
172
- }
173
- else {
174
- registeredIcon.referenceCount--;
175
- }
176
- }
177
- });
178
- return iconMap;
179
- };
180
- const getIcon = (key) => registeredIcons.get(key)?.content;
181
- class IconService {
182
- themeService = inject(SiThemeService);
183
- getIcon(name) {
184
- const camelCaseName = this.kebabToCamelCase(name);
185
- return this.themeService.themeIcons()[camelCaseName] ?? getIcon(camelCaseName);
186
- }
187
- kebabToCamelCase(str) {
188
- return str.replace(/-./g, match => match.charAt(1).toUpperCase());
189
- }
190
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
191
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, providedIn: 'root' });
192
- }
193
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: IconService, decorators: [{
194
- type: Injectable,
195
- args: [{ providedIn: 'root' }]
196
- }] });
197
-
198
246
  /**
199
247
  * Copyright (c) Siemens 2016 - 2025
200
248
  * SPDX-License-Identifier: MIT
@@ -310,80 +358,68 @@ const STATUS_ICON_CONFIG = new InjectionToken('STATUS_ICON_CONFIG', {
310
358
  * Copyright (c) Siemens 2016 - 2025
311
359
  * SPDX-License-Identifier: MIT
312
360
  */
313
- const ICON_CONFIG = new InjectionToken('ICON_CONFIG', {
314
- providedIn: 'root',
315
- factory: () => ({ disableSvgIcons: true })
316
- });
317
361
  /**
318
- * Configure how Element handles icons. Provide only once in your global configuration.
362
+ * @deprecated This component should no longer be used.
363
+ * Use the {@link SiIconComponent} instead.
364
+ * Existing usages can be replaced as follows:
319
365
  *
320
- * @experimental
321
- */
322
- const provideIconConfig = (config) => ({
323
- provide: ICON_CONFIG,
324
- useValue: config
325
- });
326
- /**
327
- * Component to render a font or SVG icon depending on the configuration.
328
- * If no SVG icon is found, the component will fall back to render the icon-font.
329
- * In that case, an application must ensure that the icon font is loaded.
330
- * This component will only attach the respective class.
366
+ * ```html
367
+ * <!-- before -->
368
+ * <si-icon icon="element-user" color="text-danger" />
369
+ * <!-- after -->
370
+ * <si-icon icon="element-user" class="icon text-danger" />
371
+ * ```
331
372
  *
332
- * The content of this component is hidden in the a11y tree.
333
- * If needed, the consumer must set proper labels.
373
+ * **Important:** Previously, the class `icon` was automatically applied. Unless not needed,
374
+ * it must now be applied manually.
375
+ * The icon class scales up the icon compared to its surrounding text.
334
376
  *
335
- * @experimental
377
+ * Stacked icons need to be constructed in HTML directly.
378
+ * If applicable, the `si-status-icon` component should be used instead.
379
+ *
380
+ * ```html
381
+ * <!-- before -->
382
+ * <si-icon
383
+ * icon="element-circle-filled"
384
+ * color="status-success"
385
+ * stackedIcon="element-state-tick"
386
+ * stackedColor="status-success-contrast"
387
+ * alt="Success"
388
+ * />
389
+ *
390
+ * <!-- after -->
391
+ * <div class="icon-stack icon" aria-label="Success">
392
+ * <si-icon icon="element-circle-filled" class="status-success" />
393
+ * <si-icon icon="element-state-tick" class="status-success-contrast" />
394
+ * </div>
395
+ * ```
336
396
  */
337
- class SiIconNextComponent {
397
+ class SiIconLegacyComponent {
398
+ /** Icon token, see {@link https://element.siemens.io/icons/element} */
399
+ icon = input();
400
+ /** Color class, see {@link https://element.siemens.io/fundamentals/typography/#color-variants-classes} */
401
+ color = input();
402
+ /** Icon token, see {@link https://element.siemens.io/fundamentals/icons/} */
403
+ stackedIcon = input();
404
+ /** Color class, see {@link https://element.siemens.io/fundamentals/icons/} */
405
+ stackedColor = input();
406
+ /** Alternative name or translation key for icon. Used for A11y. */
407
+ alt = input();
338
408
  /**
339
- * Define which icon should be rendered.
340
- * Provide using:
341
- * - value of the icon map provided by `addIcons`
342
- * - (not recommended): plain string in kebab-case or camelCase
343
- *
344
- * @example
345
- * ```ts
346
- * import { elementUser } from '@simpl/element-icons/ionic';
347
- *
348
- * @Component({template: `
349
- * <si-icon-next [icon]="icons.elementUser" />
350
- * <si-icon-next icon="element-user" />
351
- * <si-icon-next icon="elementUser" />
409
+ * Text-size class for icon size, see {@link https://element.siemens.io/fundamentals/typography/#type-styles-classes}
352
410
  *
353
- * `})
354
- * class MyComponent {
355
- * icons = addIcons(elementUser);
356
- * }
357
- * ```
411
+ * @defaultValue 'icon'
358
412
  */
359
- icon = input.required();
360
- config = inject(ICON_CONFIG);
361
- iconService = inject(IconService);
362
- svgIcon = computed(() => this.config.disableSvgIcons ? undefined : this.iconService.getIcon(this.icon()));
363
- /** Icon class, which is ensured to be kebab-case. */
364
- fontIcon = computed(() => this.svgIcon() ? undefined : this.camelToKebabCase(this.icon()));
365
- camelToKebabCase(str) {
366
- return str
367
- .replace(/([a-z])([A-Z0-9])/g, '$1-$2')
368
- .replace(/([0-9])([A-Z])/g, '$1-$2')
369
- .toLowerCase();
370
- }
371
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconNextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
372
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: SiIconNextComponent, isStandalone: true, selector: "si-icon-next", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-icon": "icon()" } }, ngImport: i0, template: ` <div
373
- aria-hidden="true"
374
- [ngClass]="svgIcon() ? '' : fontIcon()"
375
- [innerHTML]="svgIcon()"
376
- ></div>`, isInline: true, styles: [":host{display:inline-flex;font-weight:400;vertical-align:middle;line-height:1}:host ::ng-deep svg{display:block;block-size:1em;fill:currentColor}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
413
+ size = input('icon');
414
+ altText = computed(() => {
415
+ return this.alt() ?? this.icon()?.replace('element-', '').split('-').join(' ') ?? '';
416
+ });
417
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconLegacyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
418
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiIconLegacyComponent, isStandalone: true, selector: "si-icon-legacy", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, stackedIcon: { classPropertyName: "stackedIcon", publicName: "stackedIcon", isSignal: true, isRequired: false, transformFunction: null }, stackedColor: { classPropertyName: "stackedColor", publicName: "stackedColor", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\n class=\"d-inline-block position-relative\"\n [attr.aria-label]=\"altText() ? (altText() | translate) : null\"\n [attr.aria-hidden]=\"!altText()\"\n [attr.role]=\"altText() ? 'img' : 'presentation'\"\n [ngClass]=\"[icon() ?? '', color() ?? '', size()]\"\n>\n @if (stackedIcon()) {\n <i\n class=\"position-absolute start-0\"\n aria-hidden=\"true\"\n [ngClass]=\"[stackedIcon(), stackedColor() ?? '']\"\n ></i>\n }\n</span>\n", styles: [":host,span{line-height:1}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
377
419
  }
378
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconNextComponent, decorators: [{
420
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiIconLegacyComponent, decorators: [{
379
421
  type: Component,
380
- args: [{ selector: 'si-icon-next', imports: [NgClass], template: ` <div
381
- aria-hidden="true"
382
- [ngClass]="svgIcon() ? '' : fontIcon()"
383
- [innerHTML]="svgIcon()"
384
- ></div>`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
385
- '[attr.data-icon]': 'icon()'
386
- }, styles: [":host{display:inline-flex;font-weight:400;vertical-align:middle;line-height:1}:host ::ng-deep svg{display:block;block-size:1em;fill:currentColor}\n"] }]
422
+ args: [{ selector: 'si-icon-legacy', imports: [NgClass, SiTranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span\n class=\"d-inline-block position-relative\"\n [attr.aria-label]=\"altText() ? (altText() | translate) : null\"\n [attr.aria-hidden]=\"!altText()\"\n [attr.role]=\"altText() ? 'img' : 'presentation'\"\n [ngClass]=\"[icon() ?? '', color() ?? '', size()]\"\n>\n @if (stackedIcon()) {\n <i\n class=\"position-absolute start-0\"\n aria-hidden=\"true\"\n [ngClass]=\"[stackedIcon(), stackedColor() ?? '']\"\n ></i>\n }\n</span>\n", styles: [":host,span{line-height:1}\n"] }]
387
423
  }] });
388
424
 
389
425
  /**
@@ -398,22 +434,22 @@ class SiStatusIconComponent {
398
434
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiStatusIconComponent, isStandalone: true, selector: "si-status-icon", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "icon-stack" }, ngImport: i0, template: `
399
435
  @let iconValue = statusIcon();
400
436
  @if (iconValue) {
401
- <si-icon-next [ngClass]="iconValue.color" [icon]="iconValue.icon" />
402
- <si-icon-next [ngClass]="iconValue.stackedColor" [icon]="iconValue.stacked" />
437
+ <si-icon [ngClass]="iconValue.color" [icon]="iconValue.icon" />
438
+ <si-icon [ngClass]="iconValue.stackedColor" [icon]="iconValue.stacked" />
403
439
  <span class="visually-hidden">{{ iconValue.ariaLabel | translate }}</span>
404
440
  }
405
- `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SiIconNextComponent, selector: "si-icon-next", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
441
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
406
442
  }
407
443
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiStatusIconComponent, decorators: [{
408
444
  type: Component,
409
445
  args: [{
410
446
  selector: 'si-status-icon',
411
- imports: [NgClass, SiIconNextComponent, SiTranslatePipe],
447
+ imports: [NgClass, SiIconComponent, SiTranslatePipe],
412
448
  template: `
413
449
  @let iconValue = statusIcon();
414
450
  @if (iconValue) {
415
- <si-icon-next [ngClass]="iconValue.color" [icon]="iconValue.icon" />
416
- <si-icon-next [ngClass]="iconValue.stackedColor" [icon]="iconValue.stacked" />
451
+ <si-icon [ngClass]="iconValue.color" [icon]="iconValue.icon" />
452
+ <si-icon [ngClass]="iconValue.stackedColor" [icon]="iconValue.stacked" />
417
453
  <span class="visually-hidden">{{ iconValue.ariaLabel | translate }}</span>
418
454
  }
419
455
  `,
@@ -431,5 +467,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
431
467
  * Generated bundle index. Do not edit.
432
468
  */
433
469
 
434
- export { STATUS_ICON_CONFIG, SiIconComponent, SiIconModule, SiIconNextComponent, SiStatusIconComponent, addIcons, element2dEditor, elementAlarmFilled, elementAlarmTick, elementBreadcrumbRoot, elementCalendar, elementCancel, elementChecked, elementCheckedFilled, elementCircleFilled, elementDelete, elementDocument, elementDoubleLeft, elementDoubleRight, elementDown2, elementExport, elementFavorites, elementFavoritesFilled, elementHelp, elementHide, elementLeft2, elementLeft3, elementLeft4, elementLock, elementMenu, elementMinus, elementNotChecked, elementOctagonFilled, elementOk, elementOptionsVertical, elementOutOfService, elementPlus, elementRadioChecked, elementRecordFilled, elementRedo, elementRight2, elementRight3, elementRight4, elementSearch, elementShow, elementSortDown, elementSortUp, elementSoundMute, elementSoundOn, elementSquare45Filled, elementSquareFilled, elementStateExclamationMark, elementStateInfo, elementStatePause, elementStateProgress, elementStateQuestionMark, elementStateTick, elementThumbnails, elementTriangleFilled, elementUpload, elementUser, elementWarningFilled, provideIconConfig };
470
+ export { STATUS_ICON_CONFIG, SiIconComponent, SiIconLegacyComponent, SiIconModule, SiStatusIconComponent, addIcons, element2dEditor, elementAlarmFilled, elementAlarmTick, elementBreadcrumbRoot, elementCalendar, elementCancel, elementChecked, elementCheckedFilled, elementCircleFilled, elementDelete, elementDocument, elementDoubleLeft, elementDoubleRight, elementDown2, elementExport, elementFavorites, elementFavoritesFilled, elementHelp, elementHide, elementLeft2, elementLeft3, elementLeft4, elementLock, elementMenu, elementMinus, elementNotChecked, elementOctagonFilled, elementOk, elementOptionsVertical, elementOutOfService, elementPlus, elementRadioChecked, elementRecordFilled, elementRedo, elementRight2, elementRight3, elementRight4, elementSearch, elementShow, elementSortDown, elementSortUp, elementSoundMute, elementSoundOn, elementSquare45Filled, elementSquareFilled, elementStateExclamationMark, elementStateInfo, elementStatePause, elementStateProgress, elementStateQuestionMark, elementStateTick, elementThumbnails, elementTriangleFilled, elementUpload, elementUser, elementWarningFilled, provideIconConfig };
435
471
  //# sourceMappingURL=siemens-element-ng-icon.mjs.map