@hugeicons/angular 1.0.11 → 1.0.13

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.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,25 @@
1
1
  # @hugeicons/angular
2
2
 
3
3
 
4
- ## 1.0.11
4
+ ## 1.0.13
5
5
 
6
6
  ### Patch Changes
7
7
 
8
- - Updated icon counts to 6,000+ free / 60,000+ pro
8
+ - Fixed the browser tab freezing (infinite loop, memory climbing by GBs) when the `icon` input changes in apps that use `@angular/animations` (`provideAnimations()`, `BrowserAnimationsModule` or the noop variants), a regression in 1.0.12 ([#46](https://github.com/hugeicons/hugeicons/issues/46))
9
+
10
+
11
+ ## 1.0.12
12
+
13
+ ### Patch Changes
14
+
15
+ - Fixed icons rendering incompletely: every icon element is now rendered with its real tag (`circle`, `ellipse`, `rect`, … — previously all were drawn as `<path>`, e.g. `User02Icon` had no head) ([#35](https://github.com/hugeicons/hugeicons/issues/35))
16
+ - All icon attributes are now applied (`stroke-linecap`, `stroke-linejoin`, `clip-rule`, `transform`, …); stroke icons no longer render blank without a `strokeWidth` input
17
+ - Rendering is generic, like `@hugeicons/react`: any SVG element and attribute in the icon data is supported, with React's attribute naming (`strokeWidth` → `stroke-width`, `gradientTransform` kept, `xlinkHref` → `xlink:href`)
18
+ - Added `primaryColor`, `secondaryColor` and `disableSecondaryOpacity` inputs for bulk/duotone icons, matching `@hugeicons/react`
19
+ - Binding `undefined` to `size` or `color` now falls back to the defaults (24, `currentColor`), as in React
20
+ - Secondary (opacity) layers are now drawn first, the same order as `@hugeicons/react`; DOM order changes for bulk/duotone/twotone icons (update DOM snapshots if you have them)
21
+ - Verified pixel- and DOM-identical to `@hugeicons/react` for every icon in all 11 packages; works with SSR and hydration on Angular 17.1+
22
+
9
23
 
10
24
  ## 1.0.9
11
25
 
package/README.md CHANGED
@@ -238,8 +238,8 @@ The code in this package (`@hugeicons/angular`) is licensed under the MIT Licens
238
238
  This package only provides rendering utilities. It does not include or grant any rights to Hugeicons icon assets. Using Pro icon styles requires a valid Hugeicons Pro license.
239
239
 
240
240
  Hugeicons icon packs are licensed separately:
241
- - **Free icon packs**: use the license included with the specific free icon package you install.
242
- - **Pro icon packs (`@hugeicons-pro/*`)**: require a paid Hugeicons Pro license and are governed by the Hugeicons Pro Terms (see [Pro License](PRO-LICENSE.md).).
241
+ - **Free icon packs** (`@hugeicons/core-free-icons`): MIT License. The `LICENSE.md` ships in the package.
242
+ - **Pro icon packs (`@hugeicons-pro/*`)**: require a paid Hugeicons Pro license and are governed by the [Hugeicons License Agreement](https://hugeicons.com/license-agreement) (summary in the package's `PRO-LICENSE.md`).
243
243
 
244
244
 
245
245
  ## Related
package/dist/README.md CHANGED
@@ -238,8 +238,8 @@ The code in this package (`@hugeicons/angular`) is licensed under the MIT Licens
238
238
  This package only provides rendering utilities. It does not include or grant any rights to Hugeicons icon assets. Using Pro icon styles requires a valid Hugeicons Pro license.
239
239
 
240
240
  Hugeicons icon packs are licensed separately:
241
- - **Free icon packs**: use the license included with the specific free icon package you install.
242
- - **Pro icon packs (`@hugeicons-pro/*`)**: require a paid Hugeicons Pro license and are governed by the Hugeicons Pro Terms (see [Pro License](PRO-LICENSE.md).).
241
+ - **Free icon packs** (`@hugeicons/core-free-icons`): MIT License. The `LICENSE.md` ships in the package.
242
+ - **Pro icon packs (`@hugeicons-pro/*`)**: require a paid Hugeicons Pro license and are governed by the [Hugeicons License Agreement](https://hugeicons.com/license-agreement) (summary in the package's `PRO-LICENSE.md`).
243
243
 
244
244
 
245
245
  ## Related
@@ -1,12 +1,18 @@
1
- import { IconSvgObject } from '../lib/types';
1
+ import { IconSvgObject } from "../lib/types";
2
2
  import * as i0 from "@angular/core";
3
+ /**
4
+ * One SVG child of an icon: the icon data's props (React-style camelCase names)
5
+ * plus `tag`, the element name. The named fields are the ones 1.0.11 exposed.
6
+ */
3
7
  interface PathData {
4
- d: string;
5
- fill: string;
8
+ tag: string;
9
+ d?: string;
10
+ fill?: string;
6
11
  opacity?: string;
7
12
  fillRule?: string;
8
13
  stroke?: string;
9
- strokeWidth?: number;
14
+ strokeWidth?: number | string;
15
+ [prop: string]: unknown;
10
16
  }
11
17
  export declare class HugeiconsIconComponent {
12
18
  readonly size: import("@angular/core").InputSignal<string | number>;
@@ -17,8 +23,18 @@ export declare class HugeiconsIconComponent {
17
23
  readonly color: import("@angular/core").InputSignal<string>;
18
24
  readonly iconClass: import("@angular/core").InputSignal<string>;
19
25
  readonly showAlt: import("@angular/core").InputSignal<boolean>;
26
+ readonly primaryColor: import("@angular/core").InputSignal<string>;
27
+ readonly secondaryColor: import("@angular/core").InputSignal<string>;
28
+ readonly disableSecondaryOpacity: import("@angular/core").InputSignal<boolean>;
29
+ readonly resolvedSize: import("@angular/core").Signal<string | number>;
30
+ readonly mainColor: import("@angular/core").Signal<string>;
31
+ /** Stroke width/color forced by the strokeWidth input, applied to the svg and every child. */
32
+ readonly strokeOverride: import("@angular/core").Signal<{
33
+ strokeWidth: number;
34
+ stroke: string;
35
+ }>;
20
36
  readonly paths: import("@angular/core").Signal<PathData[]>;
21
37
  static ɵfac: i0.ɵɵFactoryDeclaration<HugeiconsIconComponent, never>;
22
- static ɵcmp: i0.ɵɵComponentDeclaration<HugeiconsIconComponent, "hugeicons-icon", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "strokeWidth": { "alias": "strokeWidth"; "required": false; "isSignal": true; }; "absoluteStrokeWidth": { "alias": "absoluteStrokeWidth"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "altIcon": { "alias": "altIcon"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "iconClass": { "alias": "class"; "required": false; "isSignal": true; }; "showAlt": { "alias": "showAlt"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
38
+ static ɵcmp: i0.ɵɵComponentDeclaration<HugeiconsIconComponent, "hugeicons-icon", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "strokeWidth": { "alias": "strokeWidth"; "required": false; "isSignal": true; }; "absoluteStrokeWidth": { "alias": "absoluteStrokeWidth"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "altIcon": { "alias": "altIcon"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "iconClass": { "alias": "class"; "required": false; "isSignal": true; }; "showAlt": { "alias": "showAlt"; "required": false; "isSignal": true; }; "primaryColor": { "alias": "primaryColor"; "required": false; "isSignal": true; }; "secondaryColor": { "alias": "secondaryColor"; "required": false; "isSignal": true; }; "disableSecondaryOpacity": { "alias": "disableSecondaryOpacity"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
23
39
  }
24
40
  export {};
@@ -0,0 +1,22 @@
1
+ import { OnChanges } from "@angular/core";
2
+ import * as i0 from "@angular/core";
3
+ /** One icon child: an SVG tag name plus React-style props. */
4
+ export interface SvgChildNode {
5
+ tag: string;
6
+ [prop: string]: unknown;
7
+ }
8
+ /**
9
+ * Renders icon children into the host <svg>, with any tag and any attribute, the way
10
+ * React's createElement does. A template can't bind a dynamic tag name, so the nodes
11
+ * are built through Renderer2. It runs in ngOnChanges, i.e. synchronously during
12
+ * change detection, so the icon is in the DOM right after detectChanges() and in
13
+ * server-rendered HTML. Any children already present (e.g. from SSR) are replaced.
14
+ */
15
+ export declare class HugeiconsSvgChildrenDirective implements OnChanges {
16
+ hugeiconsSvgChildren: readonly SvgChildNode[];
17
+ private readonly host;
18
+ private readonly renderer;
19
+ ngOnChanges(): void;
20
+ static ɵfac: i0.ɵɵFactoryDeclaration<HugeiconsSvgChildrenDirective, never>;
21
+ static ɵdir: i0.ɵɵDirectiveDeclaration<HugeiconsSvgChildrenDirective, "svg[hugeiconsSvgChildren]", never, { "hugeiconsSvgChildren": { "alias": "hugeiconsSvgChildren"; "required": true; }; }, {}, never, never, true, never>;
22
+ }
@@ -1,5 +1,12 @@
1
- import { Component, ChangeDetectionStrategy, computed, input } from '@angular/core';
1
+ import { Component, ChangeDetectionStrategy, computed, input, } from "@angular/core";
2
+ import { HugeiconsSvgChildrenDirective } from "./svg-children.directive";
2
3
  import * as i0 from "@angular/core";
4
+ /**
5
+ * 1.0.11 wrote fill="none" on every child it rendered (always path, circle, ellipse or
6
+ * rect). Kept for those tags so CSS such as `svg { fill: ... }` behaves as before;
7
+ * any other tag is left untouched, like React.
8
+ */
9
+ const LEGACY_FILL_NONE_TAGS = new Set(["path", "circle", "ellipse", "rect"]);
3
10
  export class HugeiconsIconComponent {
4
11
  // Signal inputs - modern Angular 17.1+ approach
5
12
  size = input(24);
@@ -7,87 +14,106 @@ export class HugeiconsIconComponent {
7
14
  absoluteStrokeWidth = input(false);
8
15
  icon = input.required();
9
16
  altIcon = input(undefined);
10
- color = input('currentColor');
11
- iconClass = input('', { alias: 'class' });
17
+ color = input("currentColor");
18
+ iconClass = input("", { alias: "class" });
12
19
  showAlt = input(false);
20
+ primaryColor = input(undefined);
21
+ secondaryColor = input(undefined);
22
+ disableSecondaryOpacity = input(false);
23
+ // Like React's default props: an explicitly bound `undefined` still falls back to the default
24
+ resolvedSize = computed(() => this.size() ?? 24);
25
+ mainColor = computed(() => this.primaryColor() || (this.color() ?? "currentColor"));
26
+ /** Stroke width/color forced by the strokeWidth input, applied to the svg and every child. */
27
+ strokeOverride = computed(() => {
28
+ const strokeWidthValue = this.strokeWidth();
29
+ if (strokeWidthValue === undefined) {
30
+ return undefined;
31
+ }
32
+ const strokeWidth = this.absoluteStrokeWidth()
33
+ ? (Number(strokeWidthValue) * 24) / Number(this.resolvedSize())
34
+ : strokeWidthValue;
35
+ return { strokeWidth, stroke: "currentColor" };
36
+ });
13
37
  // Computed signal for reactive path updates
14
38
  paths = computed(() => {
15
39
  const currentIcon = this.showAlt() && this.altIcon() ? this.altIcon() : this.icon();
16
40
  if (!currentIcon || !Array.isArray(currentIcon)) {
17
41
  return [];
18
42
  }
19
- const strokeWidthValue = this.strokeWidth();
20
- const calculatedStrokeWidth = strokeWidthValue !== undefined
21
- ? (this.absoluteStrokeWidth()
22
- ? (Number(strokeWidthValue) * 24) / Number(this.size())
23
- : strokeWidthValue)
24
- : undefined;
25
- const strokeProps = calculatedStrokeWidth !== undefined
26
- ? { strokeWidth: calculatedStrokeWidth, stroke: 'currentColor' }
27
- : {};
28
- return currentIcon.map(([_, attrs]) => ({
29
- d: attrs['d'],
30
- fill: attrs['fill'] || 'none',
31
- opacity: attrs['opacity'],
32
- fillRule: attrs['fillRule'],
33
- ...strokeProps
34
- }));
43
+ const strokeOverride = this.strokeOverride();
44
+ const mainColor = this.mainColor();
45
+ const secondaryColor = this.secondaryColor();
46
+ const disableSecondaryOpacity = this.disableSecondaryOpacity();
47
+ // Same ordering as @hugeicons/react: secondary (opacity) layers first
48
+ return [...currentIcon]
49
+ .sort(([, a], [, b]) => {
50
+ const hasOpacityA = a["opacity"] !== undefined;
51
+ const hasOpacityB = b["opacity"] !== undefined;
52
+ return hasOpacityB ? 1 : hasOpacityA ? -1 : 0;
53
+ })
54
+ .map(([tag, rawAttrs]) => {
55
+ const attrs = rawAttrs;
56
+ const isSecondary = attrs["opacity"] !== undefined;
57
+ const colorProps = secondaryColor
58
+ ? {
59
+ [attrs["stroke"] !== undefined ? "stroke" : "fill"]: isSecondary
60
+ ? secondaryColor
61
+ : mainColor,
62
+ }
63
+ : {};
64
+ return {
65
+ ...attrs,
66
+ tag,
67
+ fill: attrs["fill"] ||
68
+ (LEGACY_FILL_NONE_TAGS.has(tag) ? "none" : undefined),
69
+ ...strokeOverride,
70
+ ...colorProps,
71
+ opacity: isSecondary && !disableSecondaryOpacity
72
+ ? attrs["opacity"]
73
+ : undefined,
74
+ };
75
+ });
35
76
  });
36
77
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
37
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: HugeiconsIconComponent, isStandalone: true, selector: "hugeicons-icon", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, altIcon: { classPropertyName: "altIcon", publicName: "altIcon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconClass: { classPropertyName: "iconClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, showAlt: { classPropertyName: "showAlt", publicName: "showAlt", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: inline-flex; align-items: center; justify-content: center;" }, ngImport: i0, template: `
78
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HugeiconsIconComponent, isStandalone: true, selector: "hugeicons-icon", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, altIcon: { classPropertyName: "altIcon", publicName: "altIcon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconClass: { classPropertyName: "iconClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, showAlt: { classPropertyName: "showAlt", publicName: "showAlt", isSignal: true, isRequired: false, transformFunction: null }, primaryColor: { classPropertyName: "primaryColor", publicName: "primaryColor", isSignal: true, isRequired: false, transformFunction: null }, secondaryColor: { classPropertyName: "secondaryColor", publicName: "secondaryColor", isSignal: true, isRequired: false, transformFunction: null }, disableSecondaryOpacity: { classPropertyName: "disableSecondaryOpacity", publicName: "disableSecondaryOpacity", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: inline-flex; align-items: center; justify-content: center;" }, ngImport: i0, template: `
38
79
  <svg
39
- [attr.width]="size()"
40
- [attr.height]="size()"
80
+ [attr.width]="resolvedSize()"
81
+ [attr.height]="resolvedSize()"
41
82
  viewBox="0 0 24 24"
42
83
  fill="none"
43
- [attr.color]="color()"
84
+ [attr.color]="mainColor()"
85
+ [attr.stroke]="strokeOverride()?.stroke"
86
+ [attr.stroke-width]="strokeOverride()?.strokeWidth"
44
87
  [class]="iconClass()"
45
88
  xmlns="http://www.w3.org/2000/svg"
46
- >
47
- @for (path of paths(); track $index) {
48
- <path
49
- [attr.d]="path.d"
50
- [attr.fill]="path.fill"
51
- [attr.opacity]="path.opacity"
52
- [attr.fill-rule]="path.fillRule"
53
- [attr.stroke]="path.stroke"
54
- [attr.stroke-width]="path.strokeWidth"
55
- />
56
- }
57
- </svg>
58
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
89
+ [hugeiconsSvgChildren]="paths()"
90
+ ></svg>
91
+ `, isInline: true, dependencies: [{ kind: "directive", type: HugeiconsSvgChildrenDirective, selector: "svg[hugeiconsSvgChildren]", inputs: ["hugeiconsSvgChildren"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
59
92
  }
60
93
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsIconComponent, decorators: [{
61
94
  type: Component,
62
95
  args: [{
63
- selector: 'hugeicons-icon',
96
+ selector: "hugeicons-icon",
64
97
  standalone: true,
98
+ imports: [HugeiconsSvgChildrenDirective],
65
99
  template: `
66
100
  <svg
67
- [attr.width]="size()"
68
- [attr.height]="size()"
101
+ [attr.width]="resolvedSize()"
102
+ [attr.height]="resolvedSize()"
69
103
  viewBox="0 0 24 24"
70
104
  fill="none"
71
- [attr.color]="color()"
105
+ [attr.color]="mainColor()"
106
+ [attr.stroke]="strokeOverride()?.stroke"
107
+ [attr.stroke-width]="strokeOverride()?.strokeWidth"
72
108
  [class]="iconClass()"
73
109
  xmlns="http://www.w3.org/2000/svg"
74
- >
75
- @for (path of paths(); track $index) {
76
- <path
77
- [attr.d]="path.d"
78
- [attr.fill]="path.fill"
79
- [attr.opacity]="path.opacity"
80
- [attr.fill-rule]="path.fillRule"
81
- [attr.stroke]="path.stroke"
82
- [attr.stroke-width]="path.strokeWidth"
83
- />
84
- }
85
- </svg>
110
+ [hugeiconsSvgChildren]="paths()"
111
+ ></svg>
86
112
  `,
87
113
  host: {
88
- style: 'display: inline-flex; align-items: center; justify-content: center;'
114
+ style: "display: inline-flex; align-items: center; justify-content: center;",
89
115
  },
90
- changeDetection: ChangeDetectionStrategy.OnPush
116
+ changeDetection: ChangeDetectionStrategy.OnPush,
91
117
  }]
92
118
  }] });
93
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHVnZWljb25zLWljb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvaHVnZWljb25zLWljb24uY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsdUJBQXVCLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUEwQ3BGLE1BQU0sT0FBTyxzQkFBc0I7SUFDakMsZ0RBQWdEO0lBQ3ZDLElBQUksR0FBRyxLQUFLLENBQWtCLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLFdBQVcsR0FBRyxLQUFLLENBQXFCLFNBQVMsQ0FBQyxDQUFDO0lBQ25ELG1CQUFtQixHQUFHLEtBQUssQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUM1QyxJQUFJLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBaUIsQ0FBQztJQUN2QyxPQUFPLEdBQUcsS0FBSyxDQUE0QixTQUFTLENBQUMsQ0FBQztJQUN0RCxLQUFLLEdBQUcsS0FBSyxDQUFTLGNBQWMsQ0FBQyxDQUFDO0lBQ3RDLFNBQVMsR0FBRyxLQUFLLENBQVMsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDbEQsT0FBTyxHQUFHLEtBQUssQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUV6Qyw0Q0FBNEM7SUFDbkMsS0FBSyxHQUFHLFFBQVEsQ0FBYSxHQUFHLEVBQUU7UUFDekMsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFckYsSUFBSSxDQUFDLFdBQVcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUU7WUFDL0MsT0FBTyxFQUFFLENBQUM7U0FDWDtRQUVELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzVDLE1BQU0scUJBQXFCLEdBQUcsZ0JBQWdCLEtBQUssU0FBUztZQUMxRCxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ3pCLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3ZELENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQztZQUN2QixDQUFDLENBQUMsU0FBUyxDQUFDO1FBRWQsTUFBTSxXQUFXLEdBQUcscUJBQXFCLEtBQUssU0FBUztZQUNyRCxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRTtZQUNoRSxDQUFDLENBQUMsRUFBRSxDQUFDO1FBRVAsT0FBTyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDdEMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUM7WUFDYixJQUFJLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU07WUFDN0IsT0FBTyxFQUFFLEtBQUssQ0FBQyxTQUFTLENBQUM7WUFDekIsUUFBUSxFQUFFLEtBQUssQ0FBQyxVQUFVLENBQUM7WUFDM0IsR0FBRyxXQUFXO1NBQ2YsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDLENBQUMsQ0FBQzt3R0FyQ1Esc0JBQXNCOzRGQUF0QixzQkFBc0IsZ3NDQTNCdkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCVDs7NEZBTVUsc0JBQXNCO2tCQTlCbEMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsZ0JBQWdCO29CQUMxQixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQlQ7b0JBQ0QsSUFBSSxFQUFFO3dCQUNKLEtBQUssRUFBRSxxRUFBcUU7cUJBQzdFO29CQUNELGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNO2lCQUNoRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIGNvbXB1dGVkLCBpbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSWNvblN2Z09iamVjdCB9IGZyb20gJy4uL2xpYi90eXBlcyc7XG5cbmludGVyZmFjZSBQYXRoRGF0YSB7XG4gIGQ6IHN0cmluZztcbiAgZmlsbDogc3RyaW5nO1xuICBvcGFjaXR5Pzogc3RyaW5nO1xuICBmaWxsUnVsZT86IHN0cmluZztcbiAgc3Ryb2tlPzogc3RyaW5nO1xuICBzdHJva2VXaWR0aD86IG51bWJlcjtcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnaHVnZWljb25zLWljb24nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxzdmdcbiAgICAgIFthdHRyLndpZHRoXT1cInNpemUoKVwiXG4gICAgICBbYXR0ci5oZWlnaHRdPVwic2l6ZSgpXCJcbiAgICAgIHZpZXdCb3g9XCIwIDAgMjQgMjRcIlxuICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgW2F0dHIuY29sb3JdPVwiY29sb3IoKVwiXG4gICAgICBbY2xhc3NdPVwiaWNvbkNsYXNzKClcIlxuICAgICAgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiXG4gICAgPlxuICAgICAgQGZvciAocGF0aCBvZiBwYXRocygpOyB0cmFjayAkaW5kZXgpIHtcbiAgICAgICAgPHBhdGhcbiAgICAgICAgICBbYXR0ci5kXT1cInBhdGguZFwiXG4gICAgICAgICAgW2F0dHIuZmlsbF09XCJwYXRoLmZpbGxcIlxuICAgICAgICAgIFthdHRyLm9wYWNpdHldPVwicGF0aC5vcGFjaXR5XCJcbiAgICAgICAgICBbYXR0ci5maWxsLXJ1bGVdPVwicGF0aC5maWxsUnVsZVwiXG4gICAgICAgICAgW2F0dHIuc3Ryb2tlXT1cInBhdGguc3Ryb2tlXCJcbiAgICAgICAgICBbYXR0ci5zdHJva2Utd2lkdGhdPVwicGF0aC5zdHJva2VXaWR0aFwiXG4gICAgICAgIC8+XG4gICAgICB9XG4gICAgPC9zdmc+XG4gIGAsXG4gIGhvc3Q6IHtcbiAgICBzdHlsZTogJ2Rpc3BsYXk6IGlubGluZS1mbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsnXG4gIH0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIEh1Z2VpY29uc0ljb25Db21wb25lbnQge1xuICAvLyBTaWduYWwgaW5wdXRzIC0gbW9kZXJuIEFuZ3VsYXIgMTcuMSsgYXBwcm9hY2hcbiAgcmVhZG9ubHkgc2l6ZSA9IGlucHV0PHN0cmluZyB8IG51bWJlcj4oMjQpO1xuICByZWFkb25seSBzdHJva2VXaWR0aCA9IGlucHV0PG51bWJlciB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgcmVhZG9ubHkgYWJzb2x1dGVTdHJva2VXaWR0aCA9IGlucHV0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcmVhZG9ubHkgaWNvbiA9IGlucHV0LnJlcXVpcmVkPEljb25TdmdPYmplY3Q+KCk7XG4gIHJlYWRvbmx5IGFsdEljb24gPSBpbnB1dDxJY29uU3ZnT2JqZWN0IHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICByZWFkb25seSBjb2xvciA9IGlucHV0PHN0cmluZz4oJ2N1cnJlbnRDb2xvcicpO1xuICByZWFkb25seSBpY29uQ2xhc3MgPSBpbnB1dDxzdHJpbmc+KCcnLCB7IGFsaWFzOiAnY2xhc3MnIH0pO1xuICByZWFkb25seSBzaG93QWx0ID0gaW5wdXQ8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8vIENvbXB1dGVkIHNpZ25hbCBmb3IgcmVhY3RpdmUgcGF0aCB1cGRhdGVzXG4gIHJlYWRvbmx5IHBhdGhzID0gY29tcHV0ZWQ8UGF0aERhdGFbXT4oKCkgPT4ge1xuICAgIGNvbnN0IGN1cnJlbnRJY29uID0gdGhpcy5zaG93QWx0KCkgJiYgdGhpcy5hbHRJY29uKCkgPyB0aGlzLmFsdEljb24oKSEgOiB0aGlzLmljb24oKTtcblxuICAgIGlmICghY3VycmVudEljb24gfHwgIUFycmF5LmlzQXJyYXkoY3VycmVudEljb24pKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgY29uc3Qgc3Ryb2tlV2lkdGhWYWx1ZSA9IHRoaXMuc3Ryb2tlV2lkdGgoKTtcbiAgICBjb25zdCBjYWxjdWxhdGVkU3Ryb2tlV2lkdGggPSBzdHJva2VXaWR0aFZhbHVlICE9PSB1bmRlZmluZWRcbiAgICAgID8gKHRoaXMuYWJzb2x1dGVTdHJva2VXaWR0aCgpIFxuICAgICAgICAgID8gKE51bWJlcihzdHJva2VXaWR0aFZhbHVlKSAqIDI0KSAvIE51bWJlcih0aGlzLnNpemUoKSkgXG4gICAgICAgICAgOiBzdHJva2VXaWR0aFZhbHVlKVxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBzdHJva2VQcm9wcyA9IGNhbGN1bGF0ZWRTdHJva2VXaWR0aCAhPT0gdW5kZWZpbmVkIFxuICAgICAgPyB7IHN0cm9rZVdpZHRoOiBjYWxjdWxhdGVkU3Ryb2tlV2lkdGgsIHN0cm9rZTogJ2N1cnJlbnRDb2xvcicgfSBcbiAgICAgIDoge307XG5cbiAgICByZXR1cm4gY3VycmVudEljb24ubWFwKChbXywgYXR0cnNdKSA9PiAoe1xuICAgICAgZDogYXR0cnNbJ2QnXSxcbiAgICAgIGZpbGw6IGF0dHJzWydmaWxsJ10gfHwgJ25vbmUnLFxuICAgICAgb3BhY2l0eTogYXR0cnNbJ29wYWNpdHknXSxcbiAgICAgIGZpbGxSdWxlOiBhdHRyc1snZmlsbFJ1bGUnXSxcbiAgICAgIC4uLnN0cm9rZVByb3BzXG4gICAgfSkpO1xuICB9KTtcbn0iXX0=
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHVnZWljb25zLWljb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvaHVnZWljb25zLWljb24uY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsdUJBQXVCLEVBQ3ZCLFFBQVEsRUFDUixLQUFLLEdBQ04sTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7O0FBaUJ6RTs7OztHQUlHO0FBQ0gsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUEwQjdFLE1BQU0sT0FBTyxzQkFBc0I7SUFDakMsZ0RBQWdEO0lBQ3ZDLElBQUksR0FBRyxLQUFLLENBQWtCLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLFdBQVcsR0FBRyxLQUFLLENBQXFCLFNBQVMsQ0FBQyxDQUFDO0lBQ25ELG1CQUFtQixHQUFHLEtBQUssQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUM1QyxJQUFJLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBaUIsQ0FBQztJQUN2QyxPQUFPLEdBQUcsS0FBSyxDQUE0QixTQUFTLENBQUMsQ0FBQztJQUN0RCxLQUFLLEdBQUcsS0FBSyxDQUFTLGNBQWMsQ0FBQyxDQUFDO0lBQ3RDLFNBQVMsR0FBRyxLQUFLLENBQVMsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDbEQsT0FBTyxHQUFHLEtBQUssQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUNoQyxZQUFZLEdBQUcsS0FBSyxDQUFxQixTQUFTLENBQUMsQ0FBQztJQUNwRCxjQUFjLEdBQUcsS0FBSyxDQUFxQixTQUFTLENBQUMsQ0FBQztJQUN0RCx1QkFBdUIsR0FBRyxLQUFLLENBQVUsS0FBSyxD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UCxPQUFPO2dCQUNMLEdBQUcsS0FBSztnQkFDUixHQUFHO2dCQUNILElBQUksRUFDRCxLQUFLLENBQUMsTUFBTSxDQUF3QjtvQkFDckMsQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUN2RCxHQUFHLGNBQWM7Z0JBQ2pCLEdBQUcsVUFBVTtnQkFDYixPQUFPLEVBQ0wsV0FBVyxJQUFJLENBQUMsdUJBQXVCO29CQUNyQyxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztvQkFDbEIsQ0FBQyxDQUFDLFNBQVM7YUFDSixDQUFDO1FBQ2hCLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQyxDQUFDLENBQUM7d0dBOUVRLHNCQUFzQjs0RkFBdEIsc0JBQXNCLDhvREFwQnZCOzs7Ozs7Ozs7Ozs7O0dBYVQsNERBZFMsNkJBQTZCOzs0RkFxQjVCLHNCQUFzQjtrQkF4QmxDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLGdCQUFnQjtvQkFDMUIsVUFBVSxFQUFFLElBQUk7b0JBQ2hCLE9BQU8sRUFBRSxDQUFDLDZCQUE2QixDQUFDO29CQUN4QyxRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7R0FhVDtvQkFDRCxJQUFJLEVBQUU7d0JBQ0osS0FBSyxFQUNILHFFQUFxRTtxQkFDeEU7b0JBQ0QsZUFBZSxFQUFFLHVCQUF1QixDQUFDLE1BQU07aUJBQ2hEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgY29tcHV0ZWQsXG4gIGlucHV0LFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgSWNvblN2Z09iamVjdCB9IGZyb20gXCIuLi9saWIvdHlwZXNcIjtcbmltcG9ydCB7IEh1Z2VpY29uc1N2Z0NoaWxkcmVuRGlyZWN0aXZlIH0gZnJvbSBcIi4vc3ZnLWNoaWxkcmVuLmRpcmVjdGl2ZVwiO1xuXG4vKipcbiAqIE9uZSBTVkcgY2hpbGQgb2YgYW4gaWNvbjogdGhlIGljb24gZGF0YSdzIHByb3BzIChSZWFjdC1zdHlsZSBjYW1lbENhc2UgbmFtZXMpXG4gKiBwbHVzIGB0YWdgLCB0aGUgZWxlbWVudCBuYW1lLiBUaGUgbmFtZWQgZmllbGRzIGFyZSB0aGUgb25lcyAxLjAuMTEgZXhwb3NlZC5cbiAqL1xuaW50ZXJmYWNlIFBhdGhEYXRhIHtcbiAgdGFnOiBzdHJpbmc7XG4gIGQ/OiBzdHJpbmc7XG4gIGZpbGw/OiBzdHJpbmc7XG4gIG9wYWNpdHk/OiBzdHJpbmc7XG4gIGZpbGxSdWxlPzogc3RyaW5nO1xuICBzdHJva2U/OiBzdHJpbmc7XG4gIHN0cm9rZVdpZHRoPzogbnVtYmVyIHwgc3RyaW5nO1xuICBbcHJvcDogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuLyoqXG4gKiAxLjAuMTEgd3JvdGUgZmlsbD1cIm5vbmVcIiBvbiBldmVyeSBjaGlsZCBpdCByZW5kZXJlZCAoYWx3YXlzIHBhdGgsIGNpcmNsZSwgZWxsaXBzZSBvclxuICogcmVjdCkuIEtlcHQgZm9yIHRob3NlIHRhZ3Mgc28gQ1NTIHN1Y2ggYXMgYHN2ZyB7IGZpbGw6IC4uLiB9YCBiZWhhdmVzIGFzIGJlZm9yZTtcbiAqIGFueSBvdGhlciB0YWcgaXMgbGVmdCB1bnRvdWNoZWQsIGxpa2UgUmVhY3QuXG4gKi9cbmNvbnN0IExFR0FDWV9GSUxMX05PTkVfVEFHUyA9IG5ldyBTZXQoW1wicGF0aFwiLCBcImNpcmNsZVwiLCBcImVsbGlwc2VcIiwgXCJyZWN0XCJdKTtcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiBcImh1Z2VpY29ucy1pY29uXCIsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtIdWdlaWNvbnNTdmdDaGlsZHJlbkRpcmVjdGl2ZV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPHN2Z1xuICAgICAgW2F0dHIud2lkdGhdPVwicmVzb2x2ZWRTaXplKClcIlxuICAgICAgW2F0dHIuaGVpZ2h0XT1cInJlc29sdmVkU2l6ZSgpXCJcbiAgICAgIHZpZXdCb3g9XCIwIDAgMjQgMjRcIlxuICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgW2F0dHIuY29sb3JdPVwibWFpbkNvbG9yKClcIlxuICAgICAgW2F0dHIuc3Ryb2tlXT1cInN0cm9rZU92ZXJyaWRlKCk/LnN0cm9rZVwiXG4gICAgICBbYXR0ci5zdHJva2Utd2lkdGhdPVwic3Ryb2tlT3ZlcnJpZGUoKT8uc3Ryb2tlV2lkdGhcIlxuICAgICAgW2NsYXNzXT1cImljb25DbGFzcygpXCJcbiAgICAgIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIlxuICAgICAgW2h1Z2VpY29uc1N2Z0NoaWxkcmVuXT1cInBhdGhzKClcIlxuICAgID48L3N2Zz5cbiAgYCxcbiAgaG9zdDoge1xuICAgIHN0eWxlOlxuICAgICAgXCJkaXNwbGF5OiBpbmxpbmUtZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XCIsXG4gIH0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBIdWdlaWNvbnNJY29uQ29tcG9uZW50IHtcbiAgLy8gU2lnbmFsIGlucHV0cyAtIG1vZGVybiBBbmd1bGFyIDE3LjErIGFwcHJvYWNoXG4gIHJlYWRvbmx5IHNpemUgPSBpbnB1dDxzdHJpbmcgfCBudW1iZXI+KDI0KTtcbiAgcmVhZG9ubHkgc3Ryb2tlV2lkdGggPSBpbnB1dDxudW1iZXIgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIHJlYWRvbmx5IGFic29sdXRlU3Ryb2tlV2lkdGggPSBpbnB1dDxib29sZWFuPihmYWxzZSk7XG4gIHJlYWRvbmx5IGljb24gPSBpbnB1dC5yZXF1aXJlZDxJY29uU3ZnT2JqZWN0PigpO1xuICByZWFkb25seSBhbHRJY29uID0gaW5wdXQ8SWNvblN2Z09iamVjdCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgcmVhZG9ubHkgY29sb3IgPSBpbnB1dDxzdHJpbmc+KFwiY3VycmVudENvbG9yXCIpO1xuICByZWFkb25seSBpY29uQ2xhc3MgPSBpbnB1dDxzdHJpbmc+KFwiXCIsIHsgYWxpYXM6IFwiY2xhc3NcIiB9KTtcbiAgcmVhZG9ubHkgc2hvd0FsdCA9IGlucHV0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcmVhZG9ubHkgcHJpbWFyeUNvbG9yID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICByZWFkb25seSBzZWNvbmRhcnlDb2xvciA9IGlucHV0PHN0cmluZyB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgcmVhZG9ubHkgZGlzYWJsZVNlY29uZGFyeU9wYWNpdHkgPSBpbnB1dDxib29sZWFuPihmYWxzZSk7XG5cbiAgLy8gTGlrZSBSZWFjdCdzIGRlZmF1bHQgcHJvcHM6IGFuIGV4cGxpY2l0bHkgYm91bmQgYHVuZGVmaW5lZGAgc3RpbGwgZmFsbHMgYmFjayB0byB0aGUgZGVmYXVsdFxuICByZWFkb25seSByZXNvbHZlZFNpemUgPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNpemUoKSA/PyAyNCk7XG4gIHJlYWRvbmx5IG1haW5Db2xvciA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMucHJpbWFyeUNvbG9yKCkgfHwgKHRoaXMuY29sb3IoKSA/PyBcImN1cnJlbnRDb2xvclwiKSxcbiAgKTtcblxuICAvKiogU3Ryb2tlIHdpZHRoL2NvbG9yIGZvcmNlZCBieSB0aGUgc3Ryb2tlV2lkdGggaW5wdXQsIGFwcGxpZWQgdG8gdGhlIHN2ZyBhbmQgZXZlcnkgY2hpbGQuICovXG4gIHJlYWRvbmx5IHN0cm9rZU92ZXJyaWRlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IHN0cm9rZVdpZHRoVmFsdWUgPSB0aGlzLnN0cm9rZVdpZHRoKCk7XG4gICAgaWYgKHN0cm9rZVdpZHRoVmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3Qgc3Ryb2tlV2lkdGggPSB0aGlzLmFic29sdXRlU3Ryb2tlV2lkdGgoKVxuICAgICAgPyAoTnVtYmVyKHN0cm9rZVdpZHRoVmFsdWUpICogMjQpIC8gTnVtYmVyKHRoaXMucmVzb2x2ZWRTaXplKCkpXG4gICAgICA6IHN0cm9rZVdpZHRoVmFsdWU7XG4gICAgcmV0dXJuIHsgc3Ryb2tlV2lkdGgsIHN0cm9rZTogXCJjdXJyZW50Q29sb3JcIiB9O1xuICB9KTtcblxuICAvLyBDb21wdXRlZCBzaWduYWwgZm9yIHJlYWN0aXZlIHBhdGggdXBkYXRlc1xuICByZWFkb25seSBwYXRocyA9IGNvbXB1dGVkPFBhdGhEYXRhW10+KCgpID0+IHtcbiAgICBjb25zdCBjdXJyZW50SWNvbiA9XG4gICAgICB0aGlzLnNob3dBbHQoKSAmJiB0aGlzLmFsdEljb24oKSA/IHRoaXMuYWx0SWNvbigpISA6IHRoaXMuaWNvbigpO1xuXG4gICAgaWYgKCFjdXJyZW50SWNvbiB8fCAhQXJyYXkuaXNBcnJheShjdXJyZW50SWNvbikpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBzdHJva2VPdmVycmlkZSA9IHRoaXMuc3Ryb2tlT3ZlcnJpZGUoKTtcbiAgICBjb25zdCBtYWluQ29sb3IgPSB0aGlzLm1haW5Db2xvcigpO1xuICAgIGNvbnN0IHNlY29uZGFyeUNvbG9yID0gdGhpcy5zZWNvbmRhcnlDb2xvcigpO1xuICAgIGNvbnN0IGRpc2FibGVTZWNvbmRhcnlPcGFjaXR5ID0gdGhpcy5kaXNhYmxlU2Vjb25kYXJ5T3BhY2l0eSgpO1xuXG4gICAgLy8gU2FtZSBvcmRlcmluZyBhcyBAaHVnZWljb25zL3JlYWN0OiBzZWNvbmRhcnkgKG9wYWNpdHkpIGxheWVycyBmaXJzdFxuICAgIHJldHVybiBbLi4uY3VycmVudEljb25dXG4gICAgICAuc29ydCgoWywgYV0sIFssIGJdKSA9PiB7XG4gICAgICAgIGNvbnN0IGhhc09wYWNpdHlBID0gYVtcIm9wYWNpdHlcIl0gIT09IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgaGFzT3BhY2l0eUIgPSBiW1wib3BhY2l0eVwiXSAhPT0gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4gaGFzT3BhY2l0eUIgPyAxIDogaGFzT3BhY2l0eUEgPyAtMSA6IDA7XG4gICAgICB9KVxuICAgICAgLm1hcCgoW3RhZywgcmF3QXR0cnNdKSA9PiB7XG4gICAgICAgIGNvbnN0IGF0dHJzID0gcmF3QXR0cnMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICAgIGNvbnN0IGlzU2Vjb25kYXJ5ID0gYXR0cnNbXCJvcGFjaXR5XCJdICE9PSB1bmRlZmluZWQ7XG4gICAgICAgIGNvbnN0IGNvbG9yUHJvcHMgPSBzZWNvbmRhcnlDb2xvclxuICAgICAgICAgID8ge1xuICAgICAgICAgICAgICBbYXR0cnNbXCJzdHJva2VcIl0gIT09IHVuZGVmaW5lZCA/IFwic3Ryb2tlXCIgOiBcImZpbGxcIl06IGlzU2Vjb25kYXJ5XG4gICAgICAgICAgICAgICAgPyBzZWNvbmRhcnlDb2xvclxuICAgICAgICAgICAgICAgIDogbWFpbkNvbG9yLFxuICAgICAgICAgICAgfVxuICAgICAgICAgIDoge307XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5hdHRycyxcbiAgICAgICAgICB0YWcsXG4gICAgICAgICAgZmlsbDpcbiAgICAgICAgICAgIChhdHRyc1tcImZpbGxcIl0gYXMgc3RyaW5nIHwgdW5kZWZpbmVkKSB8fFxuICAgICAgICAgICAgKExFR0FDWV9GSUxMX05PTkVfVEFHUy5oYXModGFnKSA/IFwibm9uZVwiIDogdW5kZWZpbmVkKSxcbiAgICAgICAgICAuLi5zdHJva2VPdmVycmlkZSxcbiAgICAgICAgICAuLi5jb2xvclByb3BzLFxuICAgICAgICAgIG9wYWNpdHk6XG4gICAgICAgICAgICBpc1NlY29uZGFyeSAmJiAhZGlzYWJsZVNlY29uZGFyeU9wYWNpdHlcbiAgICAgICAgICAgICAgPyBhdHRyc1tcIm9wYWNpdHlcIl1cbiAgICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgIH0gYXMgUGF0aERhdGE7XG4gICAgICB9KTtcbiAgfSk7XG59XG4iXX0=
@@ -0,0 +1,46 @@
1
+ import { Directive, ElementRef, Input, Renderer2, inject, } from "@angular/core";
2
+ import { toSvgAttribute } from "../lib/svg-attributes";
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Renders icon children into the host <svg>, with any tag and any attribute, the way
6
+ * React's createElement does. A template can't bind a dynamic tag name, so the nodes
7
+ * are built through Renderer2. It runs in ngOnChanges, i.e. synchronously during
8
+ * change detection, so the icon is in the DOM right after detectChanges() and in
9
+ * server-rendered HTML. Any children already present (e.g. from SSR) are replaced.
10
+ */
11
+ export class HugeiconsSvgChildrenDirective {
12
+ hugeiconsSvgChildren;
13
+ host = inject(ElementRef);
14
+ renderer = inject(Renderer2);
15
+ ngOnChanges() {
16
+ const svg = this.host.nativeElement;
17
+ // Iterate over a snapshot: with @angular/animations the renderer only queues the
18
+ // removal until change detection ends, so svg.firstChild would never change.
19
+ for (const child of Array.from(svg.childNodes)) {
20
+ this.renderer.removeChild(svg, child);
21
+ }
22
+ for (const { tag, ...props } of this.hugeiconsSvgChildren ?? []) {
23
+ const child = this.renderer.createElement(tag, "svg");
24
+ for (const [prop, value] of Object.entries(props)) {
25
+ const attribute = toSvgAttribute(prop, value);
26
+ if (attribute) {
27
+ this.renderer.setAttribute(child, attribute.name, attribute.value, attribute.namespace ?? undefined);
28
+ }
29
+ }
30
+ this.renderer.appendChild(svg, child);
31
+ }
32
+ }
33
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsSvgChildrenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
34
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: HugeiconsSvgChildrenDirective, isStandalone: true, selector: "svg[hugeiconsSvgChildren]", inputs: { hugeiconsSvgChildren: "hugeiconsSvgChildren" }, usesOnChanges: true, ngImport: i0 });
35
+ }
36
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsSvgChildrenDirective, decorators: [{
37
+ type: Directive,
38
+ args: [{
39
+ selector: "svg[hugeiconsSvgChildren]",
40
+ standalone: true,
41
+ }]
42
+ }], propDecorators: { hugeiconsSvgChildren: [{
43
+ type: Input,
44
+ args: [{ required: true }]
45
+ }] } });
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ZnLWNoaWxkcmVuLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3N2Zy1jaGlsZHJlbi5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsS0FBSyxFQUVMLFNBQVMsRUFDVCxNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHVCQUF1QixDQUFDOztBQVF2RDs7Ozs7O0dBTUc7QUFLSCxNQUFNLE9BQU8sNkJBQTZCO0lBQ2Isb0JBQW9CLENBQTJCO0lBRXpELElBQUksR0FBOEIsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3JELFFBQVEsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7SUFFOUMsV0FBVztRQUNULE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBRXBDLGlGQUFpRjtRQUNqRiw2RUFBNkU7UUFDN0UsS0FBSyxNQUFNLEtBQUssSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRTtZQUM5QyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7U0FDdkM7UUFFRCxLQUFLLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxLQUFLLEVBQUUsSUFBSSxJQUFJLENBQUMsb0JBQW9CLElBQUksRUFBRSxFQUFFO1lBQy9ELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN0RCxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDakQsTUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDOUMsSUFBSSxTQUFTLEVBQUU7b0JBQ2IsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQ3hCLEtBQUssRUFDTCxTQUFTLENBQUMsSUFBSSxFQUNkLFNBQVMsQ0FBQyxLQUFLLEVBQ2YsU0FBUyxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQ2pDLENBQUM7aUJBQ0g7YUFDRjtZQUNELElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUN2QztJQUNILENBQUM7d0dBOUJVLDZCQUE2Qjs0RkFBN0IsNkJBQTZCOzs0RkFBN0IsNkJBQTZCO2tCQUp6QyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSwyQkFBMkI7b0JBQ3JDLFVBQVUsRUFBRSxJQUFJO2lCQUNqQjs4QkFFNEIsb0JBQW9CO3NCQUE5QyxLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIERpcmVjdGl2ZSxcbiAgRWxlbWVudFJlZixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgUmVuZGVyZXIyLFxuICBpbmplY3QsXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyB0b1N2Z0F0dHJpYnV0ZSB9IGZyb20gXCIuLi9saWIvc3ZnLWF0dHJpYnV0ZXNcIjtcblxuLyoqIE9uZSBpY29uIGNoaWxkOiBhbiBTVkcgdGFnIG5hbWUgcGx1cyBSZWFjdC1zdHlsZSBwcm9wcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3ZnQ2hpbGROb2RlIHtcbiAgdGFnOiBzdHJpbmc7XG4gIFtwcm9wOiBzdHJpbmddOiB1bmtub3duO1xufVxuXG4vKipcbiAqIFJlbmRlcnMgaWNvbiBjaGlsZHJlbiBpbnRvIHRoZSBob3N0IDxzdmc+LCB3aXRoIGFueSB0YWcgYW5kIGFueSBhdHRyaWJ1dGUsIHRoZSB3YXlcbiAqIFJlYWN0J3MgY3JlYXRlRWxlbWVudCBkb2VzLiBBIHRlbXBsYXRlIGNhbid0IGJpbmQgYSBkeW5hbWljIHRhZyBuYW1lLCBzbyB0aGUgbm9kZXNcbiAqIGFyZSBidWlsdCB0aHJvdWdoIFJlbmRlcmVyMi4gSXQgcnVucyBpbiBuZ09uQ2hhbmdlcywgaS5lLiBzeW5jaHJvbm91c2x5IGR1cmluZ1xuICogY2hhbmdlIGRldGVjdGlvbiwgc28gdGhlIGljb24gaXMgaW4gdGhlIERPTSByaWdodCBhZnRlciBkZXRlY3RDaGFuZ2VzKCkgYW5kIGluXG4gKiBzZXJ2ZXItcmVuZGVyZWQgSFRNTC4gQW55IGNoaWxkcmVuIGFscmVhZHkgcHJlc2VudCAoZS5nLiBmcm9tIFNTUikgYXJlIHJlcGxhY2VkLlxuICovXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6IFwic3ZnW2h1Z2VpY29uc1N2Z0NoaWxkcmVuXVwiLFxuICBzdGFuZGFsb25lOiB0cnVlLFxufSlcbmV4cG9ydCBjbGFzcyBIdWdlaWNvbnNTdmdDaGlsZHJlbkRpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIGh1Z2VpY29uc1N2Z0NoaWxkcmVuITogcmVhZG9ubHkgU3ZnQ2hpbGROb2RlW107XG5cbiAgcHJpdmF0ZSByZWFkb25seSBob3N0OiBFbGVtZW50UmVmPFNWR1NWR0VsZW1lbnQ+ID0gaW5qZWN0KEVsZW1lbnRSZWYpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlbmRlcmVyID0gaW5qZWN0KFJlbmRlcmVyMik7XG5cbiAgbmdPbkNoYW5nZXMoKTogdm9pZCB7XG4gICAgY29uc3Qgc3ZnID0gdGhpcy5ob3N0Lm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICAvLyBJdGVyYXRlIG92ZXIgYSBzbmFwc2hvdDogd2l0aCBAYW5ndWxhci9hbmltYXRpb25zIHRoZSByZW5kZXJlciBvbmx5IHF1ZXVlcyB0aGVcbiAgICAvLyByZW1vdmFsIHVudGlsIGNoYW5nZSBkZXRlY3Rpb24gZW5kcywgc28gc3ZnLmZpcnN0Q2hpbGQgd291bGQgbmV2ZXIgY2hhbmdlLlxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgQXJyYXkuZnJvbShzdmcuY2hpbGROb2RlcykpIHtcbiAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2hpbGQoc3ZnLCBjaGlsZCk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCB7IHRhZywgLi4ucHJvcHMgfSBvZiB0aGlzLmh1Z2VpY29uc1N2Z0NoaWxkcmVuID8/IFtdKSB7XG4gICAgICBjb25zdCBjaGlsZCA9IHRoaXMucmVuZGVyZXIuY3JlYXRlRWxlbWVudCh0YWcsIFwic3ZnXCIpO1xuICAgICAgZm9yIChjb25zdCBbcHJvcCwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHByb3BzKSkge1xuICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSB0b1N2Z0F0dHJpYnV0ZShwcm9wLCB2YWx1ZSk7XG4gICAgICAgIGlmIChhdHRyaWJ1dGUpIHtcbiAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNldEF0dHJpYnV0ZShcbiAgICAgICAgICAgIGNoaWxkLFxuICAgICAgICAgICAgYXR0cmlidXRlLm5hbWUsXG4gICAgICAgICAgICBhdHRyaWJ1dGUudmFsdWUsXG4gICAgICAgICAgICBhdHRyaWJ1dGUubmFtZXNwYWNlID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLnJlbmRlcmVyLmFwcGVuZENoaWxkKHN2ZywgY2hpbGQpO1xuICAgIH1cbiAgfVxufVxuIl19
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Maps the React-style prop names used by the icon data (strokeWidth, fillRule, xlinkHref …)
3
+ * to real SVG attribute names, following the same rules as React DOM:
4
+ * - names that SVG itself spells in camelCase (viewBox, gradientTransform …) are kept as-is
5
+ * - xlink / xml prefixed names get their namespace
6
+ * - every other camelCase name becomes kebab-case (strokeLinecap → stroke-linecap)
7
+ * - names that are already kebab-case or lowercase pass through unchanged
8
+ */
9
+ /** SVG attributes whose canonical spelling is camelCase. */
10
+ const CAMEL_CASE_ATTRIBUTES = new Set([
11
+ 'allowReorder', 'attributeName', 'attributeType', 'autoReverse', 'baseFrequency',
12
+ 'baseProfile', 'calcMode', 'clipPathUnits', 'contentScriptType', 'contentStyleType',
13
+ 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes', 'filterUnits',
14
+ 'glyphRef', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength',
15
+ 'keyPoints', 'keySplines', 'keyTimes', 'lengthAdjust', 'limitingConeAngle', 'markerHeight',
16
+ 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength',
17
+ 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX', 'pointsAtY',
18
+ 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY',
19
+ 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'specularConstant',
20
+ 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles',
21
+ 'surfaceScale', 'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength',
22
+ 'viewBox', 'viewTarget', 'xChannelSelector', 'yChannelSelector', 'zoomAndPan',
23
+ ]);
24
+ /** Namespaced attributes, as Renderer2 expects them: a namespace key plus the local name. */
25
+ const NAMESPACED_ATTRIBUTES = {
26
+ xlinkActuate: { name: 'actuate', namespace: 'xlink' },
27
+ xlinkArcrole: { name: 'arcrole', namespace: 'xlink' },
28
+ xlinkHref: { name: 'href', namespace: 'xlink' },
29
+ xlinkRole: { name: 'role', namespace: 'xlink' },
30
+ xlinkShow: { name: 'show', namespace: 'xlink' },
31
+ xlinkTitle: { name: 'title', namespace: 'xlink' },
32
+ xlinkType: { name: 'type', namespace: 'xlink' },
33
+ xmlBase: { name: 'base', namespace: 'xml' },
34
+ xmlLang: { name: 'lang', namespace: 'xml' },
35
+ xmlSpace: { name: 'space', namespace: 'xml' },
36
+ xmlnsXlink: { name: 'xlink', namespace: 'xmlns' },
37
+ };
38
+ /** Props React consumes itself and never writes to the DOM. */
39
+ const IGNORED_PROPS = new Set(['key', 'ref', 'children', 'dangerouslySetInnerHTML']);
40
+ export function toSvgAttribute(prop, value) {
41
+ if (IGNORED_PROPS.has(prop) || value === undefined || value === null || value === false) {
42
+ return null;
43
+ }
44
+ if (typeof value === 'function' || typeof value === 'object') {
45
+ return null;
46
+ }
47
+ const stringValue = value === true ? '' : String(value);
48
+ if (prop === 'className') {
49
+ return { name: 'class', namespace: null, value: stringValue };
50
+ }
51
+ if (prop === 'htmlFor') {
52
+ return { name: 'for', namespace: null, value: stringValue };
53
+ }
54
+ const namespaced = NAMESPACED_ATTRIBUTES[prop];
55
+ if (namespaced) {
56
+ return { name: namespaced.name, namespace: namespaced.namespace, value: stringValue };
57
+ }
58
+ if (CAMEL_CASE_ATTRIBUTES.has(prop) || !/[A-Z]/.test(prop)) {
59
+ return { name: prop, namespace: null, value: stringValue };
60
+ }
61
+ return {
62
+ name: prop.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`),
63
+ namespace: null,
64
+ value: stringValue,
65
+ };
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ZnLWF0dHJpYnV0ZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3N2Zy1hdHRyaWJ1dGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFFSCw0REFBNEQ7QUFDNUQsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNwQyxjQUFjLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsZUFBZTtJQUNoRixhQUFhLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxtQkFBbUIsRUFBRSxrQkFBa0I7SUFDbkYsaUJBQWlCLEVBQUUsVUFBVSxFQUFFLDJCQUEyQixFQUFFLFdBQVcsRUFBRSxhQUFhO0lBQ3RGLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGtCQUFrQjtJQUNwRixXQUFXLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsbUJBQW1CLEVBQUUsY0FBYztJQUMxRixhQUFhLEVBQUUsYUFBYSxFQUFFLGtCQUFrQixFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsWUFBWTtJQUN6RixxQkFBcUIsRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsV0FBVyxFQUFFLFdBQVc7SUFDbkYsV0FBVyxFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsTUFBTTtJQUNyRixhQUFhLEVBQUUsV0FBVyxFQUFFLG9CQUFvQixFQUFFLGtCQUFrQixFQUFFLGtCQUFrQjtJQUN4RixrQkFBa0IsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLGNBQWMsRUFBRSxhQUFhO0lBQ2hGLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxZQUFZO0lBQ25GLFNBQVMsRUFBRSxZQUFZLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsWUFBWTtDQUM5RSxDQUFDLENBQUM7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Q0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDaEUsU0FBUyxFQUFFLElBQUk7UUFDZixLQUFLLEVBQUUsV0FBVztLQUNuQixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWFwcyB0aGUgUmVhY3Qtc3R5bGUgcHJvcCBuYW1lcyB1c2VkIGJ5IHRoZSBpY29uIGRhdGEgKHN0cm9rZVdpZHRoLCBmaWxsUnVsZSwgeGxpbmtIcmVmIOKApilcbiAqIHRvIHJlYWwgU1ZHIGF0dHJpYnV0ZSBuYW1lcywgZm9sbG93aW5nIHRoZSBzYW1lIHJ1bGVzIGFzIFJlYWN0IERPTTpcbiAqIC0gbmFtZXMgdGhhdCBTVkcgaXRzZWxmIHNwZWxscyBpbiBjYW1lbENhc2UgKHZpZXdCb3gsIGdyYWRpZW50VHJhbnNmb3JtIOKApikgYXJlIGtlcHQgYXMtaXNcbiAqIC0geGxpbmsgLyB4bWwgcHJlZml4ZWQgbmFtZXMgZ2V0IHRoZWlyIG5hbWVzcGFjZVxuICogLSBldmVyeSBvdGhlciBjYW1lbENhc2UgbmFtZSBiZWNvbWVzIGtlYmFiLWNhc2UgKHN0cm9rZUxpbmVjYXAg4oaSIHN0cm9rZS1saW5lY2FwKVxuICogLSBuYW1lcyB0aGF0IGFyZSBhbHJlYWR5IGtlYmFiLWNhc2Ugb3IgbG93ZXJjYXNlIHBhc3MgdGhyb3VnaCB1bmNoYW5nZWRcbiAqL1xuXG4vKiogU1ZHIGF0dHJpYnV0ZXMgd2hvc2UgY2Fub25pY2FsIHNwZWxsaW5nIGlzIGNhbWVsQ2FzZS4gKi9cbmNvbnN0IENBTUVMX0NBU0VfQVRUUklCVVRFUyA9IG5ldyBTZXQoW1xuICAnYWxsb3dSZW9yZGVyJywgJ2F0dHJpYnV0ZU5hbWUnLCAnYXR0cmlidXRlVHlwZScsICdhdXRvUmV2ZXJzZScsICdiYXNlRnJlcXVlbmN5JyxcbiAgJ2Jhc2VQcm9maWxlJywgJ2NhbGNNb2RlJywgJ2NsaXBQYXRoVW5pdHMnLCAnY29udGVudFNjcmlwdFR5cGUnLCAnY29udGVudFN0eWxlVHlwZScsXG4gICdkaWZmdXNlQ29uc3RhbnQnLCAnZWRnZU1vZGUnLCAnZXh0ZXJuYWxSZXNvdXJjZXNSZXF1aXJlZCcsICdmaWx0ZXJSZXMnLCAnZmlsdGVyVW5pdHMnLFxuICAnZ2x5cGhSZWYnLCAnZ3JhZGllbnRUcmFuc2Zvcm0nLCAnZ3JhZGllbnRVbml0cycsICdrZXJuZWxNYXRyaXgnLCAna2VybmVsVW5pdExlbmd0aCcsXG4gICdrZXlQb2ludHMnLCAna2V5U3BsaW5lcycsICdrZXlUaW1lcycsICdsZW5ndGhBZGp1c3QnLCAnbGltaXRpbmdDb25lQW5nbGUnLCAnbWFya2VySGVpZ2h0JyxcbiAgJ21hcmtlclVuaXRzJywgJ21hcmtlcldpZHRoJywgJ21hc2tDb250ZW50VW5pdHMnLCAnbWFza1VuaXRzJywgJ251bU9jdGF2ZXMnLCAncGF0aExlbmd0aCcsXG4gICdwYXR0ZXJuQ29udGVudFVuaXRzJywgJ3BhdHRlcm5UcmFuc2Zvcm0nLCAncGF0dGVyblVuaXRzJywgJ3BvaW50c0F0WCcsICdwb2ludHNBdFknLFxuICAncG9pbnRzQXRaJywgJ3ByZXNlcnZlQWxwaGEnLCAncHJlc2VydmVBc3BlY3RSYXRpbycsICdwcmltaXRpdmVVbml0cycsICdyZWZYJywgJ3JlZlknLFxuICAncmVwZWF0Q291bnQnLCAncmVwZWF0RHVyJywgJ3JlcXVpcmVkRXh0ZW5zaW9ucycsICdyZXF1aXJlZEZlYXR1cmVzJywgJ3NwZWN1bGFyQ29uc3RhbnQnLFxuICAnc3BlY3VsYXJFeHBvbmVudCcsICdzcHJlYWRNZXRob2QnLCAnc3RhcnRPZmZzZXQnLCAnc3RkRGV2aWF0aW9uJywgJ3N0aXRjaFRpbGVzJyxcbiAgJ3N1cmZhY2VTY2FsZScsICdzeXN0ZW1MYW5ndWFnZScsICd0YWJsZVZhbHVlcycsICd0YXJnZXRYJywgJ3RhcmdldFknLCAndGV4dExlbmd0aCcsXG4gICd2aWV3Qm94JywgJ3ZpZXdUYXJnZXQnLCAneENoYW5uZWxTZWxlY3RvcicsICd5Q2hhbm5lbFNlbGVjdG9yJywgJ3pvb21BbmRQYW4nLFxuXSk7XG5cbi8qKiBOYW1lc3BhY2VkIGF0dHJpYnV0ZXMsIGFzIFJlbmRlcmVyMiBleHBlY3RzIHRoZW06IGEgbmFtZXNwYWNlIGtleSBwbHVzIHRoZSBsb2NhbCBuYW1lLiAqL1xuY29uc3QgTkFNRVNQQUNFRF9BVFRSSUJVVEVTOiBSZWNvcmQ8c3RyaW5nLCB7IG5hbWU6IHN0cmluZzsgbmFtZXNwYWNlOiBzdHJpbmcgfT4gPSB7XG4gIHhsaW5rQWN0dWF0ZTogeyBuYW1lOiAnYWN0dWF0ZScsIG5hbWVzcGFjZTogJ3hsaW5rJyB9LFxuICB4bGlua0FyY3JvbGU6IHsgbmFtZTogJ2FyY3JvbGUnLCBuYW1lc3BhY2U6ICd4bGluaycgfSxcbiAgeGxpbmtIcmVmOiB7IG5hbWU6ICdocmVmJywgbmFtZXNwYWNlOiAneGxpbmsnIH0sXG4gIHhsaW5rUm9sZTogeyBuYW1lOiAncm9sZScsIG5hbWVzcGFjZTogJ3hsaW5rJyB9LFxuICB4bGlua1Nob3c6IHsgbmFtZTogJ3Nob3cnLCBuYW1lc3BhY2U6ICd4bGluaycgfSxcbiAgeGxpbmtUaXRsZTogeyBuYW1lOiAndGl0bGUnLCBuYW1lc3BhY2U6ICd4bGluaycgfSxcbiAgeGxpbmtUeXBlOiB7IG5hbWU6ICd0eXBlJywgbmFtZXNwYWNlOiAneGxpbmsnIH0sXG4gIHhtbEJhc2U6IHsgbmFtZTogJ2Jhc2UnLCBuYW1lc3BhY2U6ICd4bWwnIH0sXG4gIHhtbExhbmc6IHsgbmFtZTogJ2xhbmcnLCBuYW1lc3BhY2U6ICd4bWwnIH0sXG4gIHhtbFNwYWNlOiB7IG5hbWU6ICdzcGFjZScsIG5hbWVzcGFjZTogJ3htbCcgfSxcbiAgeG1sbnNYbGluazogeyBuYW1lOiAneGxpbmsnLCBuYW1lc3BhY2U6ICd4bWxucycgfSxcbn07XG5cbi8qKiBQcm9wcyBSZWFjdCBjb25zdW1lcyBpdHNlbGYgYW5kIG5ldmVyIHdyaXRlcyB0byB0aGUgRE9NLiAqL1xuY29uc3QgSUdOT1JFRF9QUk9QUyA9IG5ldyBTZXQoWydrZXknLCAncmVmJywgJ2NoaWxkcmVuJywgJ2Rhbmdlcm91c2x5U2V0SW5uZXJIVE1MJ10pO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN2Z0F0dHJpYnV0ZSB7XG4gIC8qKiBMb2NhbCBhdHRyaWJ1dGUgbmFtZSAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBSZW5kZXJlcjIgbmFtZXNwYWNlIGtleSAoeGxpbmssIHhtbCwgeG1sbnMpIG9yIG51bGwgKi9cbiAgbmFtZXNwYWNlOiBzdHJpbmcgfCBudWxsO1xuICB2YWx1ZTogc3RyaW5nO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9TdmdBdHRyaWJ1dGUocHJvcDogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IFN2Z0F0dHJpYnV0ZSB8IG51bGwge1xuICBpZiAoSUdOT1JFRF9QUk9QUy5oYXMocHJvcCkgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCBzdHJpbmdWYWx1ZSA9IHZhbHVlID09PSB0cnVlID8gJycgOiBTdHJpbmcodmFsdWUpO1xuXG4gIGlmIChwcm9wID09PSAnY2xhc3NOYW1lJykge1xuICAgIHJldHVybiB7IG5hbWU6ICdjbGFzcycsIG5hbWVzcGFjZTogbnVsbCwgdmFsdWU6IHN0cmluZ1ZhbHVlIH07XG4gIH1cbiAgaWYgKHByb3AgPT09ICdodG1sRm9yJykge1xuICAgIHJldHVybiB7IG5hbWU6ICdmb3InLCBuYW1lc3BhY2U6IG51bGwsIHZhbHVlOiBzdHJpbmdWYWx1ZSB9O1xuICB9XG4gIGNvbnN0IG5hbWVzcGFjZWQgPSBOQU1FU1BBQ0VEX0FUVFJJQlVURVNbcHJvcF07XG4gIGlmIChuYW1lc3BhY2VkKSB7XG4gICAgcmV0dXJuIHsgbmFtZTogbmFtZXNwYWNlZC5uYW1lLCBuYW1lc3BhY2U6IG5hbWVzcGFjZWQubmFtZXNwYWNlLCB2YWx1ZTogc3RyaW5nVmFsdWUgfTtcbiAgfVxuICBpZiAoQ0FNRUxfQ0FTRV9BVFRSSUJVVEVTLmhhcyhwcm9wKSB8fCAhL1tBLVpdLy50ZXN0KHByb3ApKSB7XG4gICAgcmV0dXJuIHsgbmFtZTogcHJvcCwgbmFtZXNwYWNlOiBudWxsLCB2YWx1ZTogc3RyaW5nVmFsdWUgfTtcbiAgfVxuICByZXR1cm4ge1xuICAgIG5hbWU6IHByb3AucmVwbGFjZSgvW0EtWl0vZywgKGNoYXIpID0+IGAtJHtjaGFyLnRvTG93ZXJDYXNlKCl9YCksXG4gICAgbmFtZXNwYWNlOiBudWxsLFxuICAgIHZhbHVlOiBzdHJpbmdWYWx1ZSxcbiAgfTtcbn1cbiJdfQ==
@@ -1,2 +1,2 @@
1
1
  export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKiogU1ZHIHBhdGggYXR0cmlidXRlcyAtIHN0cmljdCB2ZXJzaW9uIHdpdGggcmVxdWlyZWQgZCBwcm9wZXJ0eSAqL1xuZXhwb3J0IGludGVyZmFjZSBTdmdQYXRoQXR0cmlidXRlcyB7XG4gIGQ6IHN0cmluZztcbiAgZmlsbD86IHN0cmluZztcbiAgb3BhY2l0eT86IHN0cmluZztcbiAgZmlsbFJ1bGU/OiAnbm9uemVybycgfCAnZXZlbm9kZCc7XG4gIHN0cm9rZT86IHN0cmluZztcbiAgc3Ryb2tlV2lkdGg/OiBudW1iZXIgfCBzdHJpbmc7XG4gIHN0cm9rZUxpbmVjYXA/OiAnYnV0dCcgfCAncm91bmQnIHwgJ3NxdWFyZSc7XG4gIHN0cm9rZUxpbmVqb2luPzogJ21pdGVyJyB8ICdyb3VuZCcgfCAnYmV2ZWwnO1xuICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xufVxuXG4vKiogTG9vc2UgcGF0aCBhdHRyaWJ1dGVzIHR5cGUgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBpY29uIGRhdGEgcGFja2FnZXMgKi9cbmV4cG9ydCB0eXBlIExvb3NlU3ZnUGF0aEF0dHJpYnV0ZXMgPSB7XG4gIGQ/OiBzdHJpbmc7XG4gIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZDtcbn07XG5cbi8qKiBJY29uIFNWRyBvYmplY3QgdHlwZSAtIGFjY2VwdHMgYm90aCBzdHJpY3QgYW5kIGxvb3NlIHBhdGggYXR0cmlidXRlIGZvcm1hdHMgKi9cbmV4cG9ydCB0eXBlIEljb25TdmdPYmplY3QgPSByZWFkb25seSAocmVhZG9ubHkgW3N0cmluZywgU3ZnUGF0aEF0dHJpYnV0ZXMgfCBMb29zZVN2Z1BhdGhBdHRyaWJ1dGVzXSlbXTtcblxuZXhwb3J0IHR5cGUgSWNvbk5hbWUgPSBzdHJpbmc7XG5cbi8qKiBJY29uIHN0eWxlIHZhcmlhbnRzICovXG5leHBvcnQgdHlwZSBJY29uU3R5bGUgPSBcbiAgfCAnc3Ryb2tlLXJvdW5kZWQnXG4gIHwgJ3N0cm9rZS1zaGFycCdcbiAgfCAnc3Ryb2tlLXN0YW5kYXJkJ1xuICB8ICdzb2xpZC1yb3VuZGVkJ1xuICB8ICdzb2xpZC1zaGFycCdcbiAgfCAnc29saWQtc3RhbmRhcmQnXG4gIHwgJ2J1bGstcm91bmRlZCdcbiAgfCAnZHVvdG9uZS1yb3VuZGVkJ1xuICB8ICdkdW90b25lLXN0YW5kYXJkJ1xuICB8ICd0d290b25lLXJvdW5kZWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEljb25NZXRhZGF0YSB7XG4gIG5hbWU6IEljb25OYW1lO1xuICBjYXRlZ29yeTogc3RyaW5nO1xuICB0YWdzOiBzdHJpbmdbXTtcbiAgcGFjazogc3RyaW5nO1xuICBzdHlsZT86IEljb25TdHlsZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJY29uRGF0YSB7XG4gIGljb246IEljb25TdmdPYmplY3Q7XG4gIG1ldGFkYXRhOiBJY29uTWV0YWRhdGE7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSHVnZWljb25zUHJvcHMge1xuICBzaXplPzogc3RyaW5nIHwgbnVtYmVyO1xuICBzdHJva2VXaWR0aD86IG51bWJlcjtcbiAgYWJzb2x1dGVTdHJva2VXaWR0aD86IGJvb2xlYW47XG4gIGljb246IEljb25TdmdPYmplY3Q7XG4gIGFsdEljb24/OiBJY29uU3ZnT2JqZWN0O1xuICBjb2xvcj86IHN0cmluZztcbiAgY2xhc3M/OiBzdHJpbmc7XG4gIHNob3dBbHQ/OiBib29sZWFuO1xufSAiXX0=
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKiogU1ZHIHBhdGggYXR0cmlidXRlcyAtIHN0cmljdCB2ZXJzaW9uIHdpdGggcmVxdWlyZWQgZCBwcm9wZXJ0eSAqL1xuZXhwb3J0IGludGVyZmFjZSBTdmdQYXRoQXR0cmlidXRlcyB7XG4gIGQ6IHN0cmluZztcbiAgZmlsbD86IHN0cmluZztcbiAgb3BhY2l0eT86IHN0cmluZztcbiAgZmlsbFJ1bGU/OiAnbm9uemVybycgfCAnZXZlbm9kZCc7XG4gIHN0cm9rZT86IHN0cmluZztcbiAgc3Ryb2tlV2lkdGg/OiBudW1iZXIgfCBzdHJpbmc7XG4gIHN0cm9rZUxpbmVjYXA/OiAnYnV0dCcgfCAncm91bmQnIHwgJ3NxdWFyZSc7XG4gIHN0cm9rZUxpbmVqb2luPzogJ21pdGVyJyB8ICdyb3VuZCcgfCAnYmV2ZWwnO1xuICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xufVxuXG4vKiogTG9vc2UgcGF0aCBhdHRyaWJ1dGVzIHR5cGUgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBpY29uIGRhdGEgcGFja2FnZXMgKi9cbmV4cG9ydCB0eXBlIExvb3NlU3ZnUGF0aEF0dHJpYnV0ZXMgPSB7XG4gIGQ/OiBzdHJpbmc7XG4gIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZDtcbn07XG5cbi8qKiBJY29uIFNWRyBvYmplY3QgdHlwZSAtIGFjY2VwdHMgYm90aCBzdHJpY3QgYW5kIGxvb3NlIHBhdGggYXR0cmlidXRlIGZvcm1hdHMgKi9cbmV4cG9ydCB0eXBlIEljb25TdmdPYmplY3QgPSByZWFkb25seSAocmVhZG9ubHkgW3N0cmluZywgU3ZnUGF0aEF0dHJpYnV0ZXMgfCBMb29zZVN2Z1BhdGhBdHRyaWJ1dGVzXSlbXTtcblxuZXhwb3J0IHR5cGUgSWNvbk5hbWUgPSBzdHJpbmc7XG5cbi8qKiBJY29uIHN0eWxlIHZhcmlhbnRzICovXG5leHBvcnQgdHlwZSBJY29uU3R5bGUgPSBcbiAgfCAnc3Ryb2tlLXJvdW5kZWQnXG4gIHwgJ3N0cm9rZS1zaGFycCdcbiAgfCAnc3Ryb2tlLXN0YW5kYXJkJ1xuICB8ICdzb2xpZC1yb3VuZGVkJ1xuICB8ICdzb2xpZC1zaGFycCdcbiAgfCAnc29saWQtc3RhbmRhcmQnXG4gIHwgJ2J1bGstcm91bmRlZCdcbiAgfCAnZHVvdG9uZS1yb3VuZGVkJ1xuICB8ICdkdW90b25lLXN0YW5kYXJkJ1xuICB8ICd0d290b25lLXJvdW5kZWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEljb25NZXRhZGF0YSB7XG4gIG5hbWU6IEljb25OYW1lO1xuICBjYXRlZ29yeTogc3RyaW5nO1xuICB0YWdzOiBzdHJpbmdbXTtcbiAgcGFjazogc3RyaW5nO1xuICBzdHlsZT86IEljb25TdHlsZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJY29uRGF0YSB7XG4gIGljb246IEljb25TdmdPYmplY3Q7XG4gIG1ldGFkYXRhOiBJY29uTWV0YWRhdGE7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSHVnZWljb25zUHJvcHMge1xuICBzaXplPzogc3RyaW5nIHwgbnVtYmVyO1xuICBzdHJva2VXaWR0aD86IG51bWJlcjtcbiAgYWJzb2x1dGVTdHJva2VXaWR0aD86IGJvb2xlYW47XG4gIGljb246IEljb25TdmdPYmplY3Q7XG4gIGFsdEljb24/OiBJY29uU3ZnT2JqZWN0O1xuICBjb2xvcj86IHN0cmluZztcbiAgY2xhc3M/OiBzdHJpbmc7XG4gIHNob3dBbHQ/OiBib29sZWFuO1xuICBwcmltYXJ5Q29sb3I/OiBzdHJpbmc7XG4gIHNlY29uZGFyeUNvbG9yPzogc3RyaW5nO1xuICBkaXNhYmxlU2Vjb25kYXJ5T3BhY2l0eT86IGJvb2xlYW47XG59ICJdfQ==
@@ -1,6 +1,122 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, ElementRef, Renderer2, Input, Directive, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
 
4
+ /**
5
+ * Maps the React-style prop names used by the icon data (strokeWidth, fillRule, xlinkHref …)
6
+ * to real SVG attribute names, following the same rules as React DOM:
7
+ * - names that SVG itself spells in camelCase (viewBox, gradientTransform …) are kept as-is
8
+ * - xlink / xml prefixed names get their namespace
9
+ * - every other camelCase name becomes kebab-case (strokeLinecap → stroke-linecap)
10
+ * - names that are already kebab-case or lowercase pass through unchanged
11
+ */
12
+ /** SVG attributes whose canonical spelling is camelCase. */
13
+ const CAMEL_CASE_ATTRIBUTES = new Set([
14
+ 'allowReorder', 'attributeName', 'attributeType', 'autoReverse', 'baseFrequency',
15
+ 'baseProfile', 'calcMode', 'clipPathUnits', 'contentScriptType', 'contentStyleType',
16
+ 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes', 'filterUnits',
17
+ 'glyphRef', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength',
18
+ 'keyPoints', 'keySplines', 'keyTimes', 'lengthAdjust', 'limitingConeAngle', 'markerHeight',
19
+ 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength',
20
+ 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX', 'pointsAtY',
21
+ 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY',
22
+ 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'specularConstant',
23
+ 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles',
24
+ 'surfaceScale', 'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength',
25
+ 'viewBox', 'viewTarget', 'xChannelSelector', 'yChannelSelector', 'zoomAndPan',
26
+ ]);
27
+ /** Namespaced attributes, as Renderer2 expects them: a namespace key plus the local name. */
28
+ const NAMESPACED_ATTRIBUTES = {
29
+ xlinkActuate: { name: 'actuate', namespace: 'xlink' },
30
+ xlinkArcrole: { name: 'arcrole', namespace: 'xlink' },
31
+ xlinkHref: { name: 'href', namespace: 'xlink' },
32
+ xlinkRole: { name: 'role', namespace: 'xlink' },
33
+ xlinkShow: { name: 'show', namespace: 'xlink' },
34
+ xlinkTitle: { name: 'title', namespace: 'xlink' },
35
+ xlinkType: { name: 'type', namespace: 'xlink' },
36
+ xmlBase: { name: 'base', namespace: 'xml' },
37
+ xmlLang: { name: 'lang', namespace: 'xml' },
38
+ xmlSpace: { name: 'space', namespace: 'xml' },
39
+ xmlnsXlink: { name: 'xlink', namespace: 'xmlns' },
40
+ };
41
+ /** Props React consumes itself and never writes to the DOM. */
42
+ const IGNORED_PROPS = new Set(['key', 'ref', 'children', 'dangerouslySetInnerHTML']);
43
+ function toSvgAttribute(prop, value) {
44
+ if (IGNORED_PROPS.has(prop) || value === undefined || value === null || value === false) {
45
+ return null;
46
+ }
47
+ if (typeof value === 'function' || typeof value === 'object') {
48
+ return null;
49
+ }
50
+ const stringValue = value === true ? '' : String(value);
51
+ if (prop === 'className') {
52
+ return { name: 'class', namespace: null, value: stringValue };
53
+ }
54
+ if (prop === 'htmlFor') {
55
+ return { name: 'for', namespace: null, value: stringValue };
56
+ }
57
+ const namespaced = NAMESPACED_ATTRIBUTES[prop];
58
+ if (namespaced) {
59
+ return { name: namespaced.name, namespace: namespaced.namespace, value: stringValue };
60
+ }
61
+ if (CAMEL_CASE_ATTRIBUTES.has(prop) || !/[A-Z]/.test(prop)) {
62
+ return { name: prop, namespace: null, value: stringValue };
63
+ }
64
+ return {
65
+ name: prop.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`),
66
+ namespace: null,
67
+ value: stringValue,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Renders icon children into the host <svg>, with any tag and any attribute, the way
73
+ * React's createElement does. A template can't bind a dynamic tag name, so the nodes
74
+ * are built through Renderer2. It runs in ngOnChanges, i.e. synchronously during
75
+ * change detection, so the icon is in the DOM right after detectChanges() and in
76
+ * server-rendered HTML. Any children already present (e.g. from SSR) are replaced.
77
+ */
78
+ class HugeiconsSvgChildrenDirective {
79
+ hugeiconsSvgChildren;
80
+ host = inject(ElementRef);
81
+ renderer = inject(Renderer2);
82
+ ngOnChanges() {
83
+ const svg = this.host.nativeElement;
84
+ // Iterate over a snapshot: with @angular/animations the renderer only queues the
85
+ // removal until change detection ends, so svg.firstChild would never change.
86
+ for (const child of Array.from(svg.childNodes)) {
87
+ this.renderer.removeChild(svg, child);
88
+ }
89
+ for (const { tag, ...props } of this.hugeiconsSvgChildren ?? []) {
90
+ const child = this.renderer.createElement(tag, "svg");
91
+ for (const [prop, value] of Object.entries(props)) {
92
+ const attribute = toSvgAttribute(prop, value);
93
+ if (attribute) {
94
+ this.renderer.setAttribute(child, attribute.name, attribute.value, attribute.namespace ?? undefined);
95
+ }
96
+ }
97
+ this.renderer.appendChild(svg, child);
98
+ }
99
+ }
100
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsSvgChildrenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
101
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: HugeiconsSvgChildrenDirective, isStandalone: true, selector: "svg[hugeiconsSvgChildren]", inputs: { hugeiconsSvgChildren: "hugeiconsSvgChildren" }, usesOnChanges: true, ngImport: i0 });
102
+ }
103
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsSvgChildrenDirective, decorators: [{
104
+ type: Directive,
105
+ args: [{
106
+ selector: "svg[hugeiconsSvgChildren]",
107
+ standalone: true,
108
+ }]
109
+ }], propDecorators: { hugeiconsSvgChildren: [{
110
+ type: Input,
111
+ args: [{ required: true }]
112
+ }] } });
113
+
114
+ /**
115
+ * 1.0.11 wrote fill="none" on every child it rendered (always path, circle, ellipse or
116
+ * rect). Kept for those tags so CSS such as `svg { fill: ... }` behaves as before;
117
+ * any other tag is left untouched, like React.
118
+ */
119
+ const LEGACY_FILL_NONE_TAGS = new Set(["path", "circle", "ellipse", "rect"]);
4
120
  class HugeiconsIconComponent {
5
121
  // Signal inputs - modern Angular 17.1+ approach
6
122
  size = input(24);
@@ -8,87 +124,106 @@ class HugeiconsIconComponent {
8
124
  absoluteStrokeWidth = input(false);
9
125
  icon = input.required();
10
126
  altIcon = input(undefined);
11
- color = input('currentColor');
12
- iconClass = input('', { alias: 'class' });
127
+ color = input("currentColor");
128
+ iconClass = input("", { alias: "class" });
13
129
  showAlt = input(false);
130
+ primaryColor = input(undefined);
131
+ secondaryColor = input(undefined);
132
+ disableSecondaryOpacity = input(false);
133
+ // Like React's default props: an explicitly bound `undefined` still falls back to the default
134
+ resolvedSize = computed(() => this.size() ?? 24);
135
+ mainColor = computed(() => this.primaryColor() || (this.color() ?? "currentColor"));
136
+ /** Stroke width/color forced by the strokeWidth input, applied to the svg and every child. */
137
+ strokeOverride = computed(() => {
138
+ const strokeWidthValue = this.strokeWidth();
139
+ if (strokeWidthValue === undefined) {
140
+ return undefined;
141
+ }
142
+ const strokeWidth = this.absoluteStrokeWidth()
143
+ ? (Number(strokeWidthValue) * 24) / Number(this.resolvedSize())
144
+ : strokeWidthValue;
145
+ return { strokeWidth, stroke: "currentColor" };
146
+ });
14
147
  // Computed signal for reactive path updates
15
148
  paths = computed(() => {
16
149
  const currentIcon = this.showAlt() && this.altIcon() ? this.altIcon() : this.icon();
17
150
  if (!currentIcon || !Array.isArray(currentIcon)) {
18
151
  return [];
19
152
  }
20
- const strokeWidthValue = this.strokeWidth();
21
- const calculatedStrokeWidth = strokeWidthValue !== undefined
22
- ? (this.absoluteStrokeWidth()
23
- ? (Number(strokeWidthValue) * 24) / Number(this.size())
24
- : strokeWidthValue)
25
- : undefined;
26
- const strokeProps = calculatedStrokeWidth !== undefined
27
- ? { strokeWidth: calculatedStrokeWidth, stroke: 'currentColor' }
28
- : {};
29
- return currentIcon.map(([_, attrs]) => ({
30
- d: attrs['d'],
31
- fill: attrs['fill'] || 'none',
32
- opacity: attrs['opacity'],
33
- fillRule: attrs['fillRule'],
34
- ...strokeProps
35
- }));
153
+ const strokeOverride = this.strokeOverride();
154
+ const mainColor = this.mainColor();
155
+ const secondaryColor = this.secondaryColor();
156
+ const disableSecondaryOpacity = this.disableSecondaryOpacity();
157
+ // Same ordering as @hugeicons/react: secondary (opacity) layers first
158
+ return [...currentIcon]
159
+ .sort(([, a], [, b]) => {
160
+ const hasOpacityA = a["opacity"] !== undefined;
161
+ const hasOpacityB = b["opacity"] !== undefined;
162
+ return hasOpacityB ? 1 : hasOpacityA ? -1 : 0;
163
+ })
164
+ .map(([tag, rawAttrs]) => {
165
+ const attrs = rawAttrs;
166
+ const isSecondary = attrs["opacity"] !== undefined;
167
+ const colorProps = secondaryColor
168
+ ? {
169
+ [attrs["stroke"] !== undefined ? "stroke" : "fill"]: isSecondary
170
+ ? secondaryColor
171
+ : mainColor,
172
+ }
173
+ : {};
174
+ return {
175
+ ...attrs,
176
+ tag,
177
+ fill: attrs["fill"] ||
178
+ (LEGACY_FILL_NONE_TAGS.has(tag) ? "none" : undefined),
179
+ ...strokeOverride,
180
+ ...colorProps,
181
+ opacity: isSecondary && !disableSecondaryOpacity
182
+ ? attrs["opacity"]
183
+ : undefined,
184
+ };
185
+ });
36
186
  });
37
187
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
38
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: HugeiconsIconComponent, isStandalone: true, selector: "hugeicons-icon", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, altIcon: { classPropertyName: "altIcon", publicName: "altIcon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconClass: { classPropertyName: "iconClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, showAlt: { classPropertyName: "showAlt", publicName: "showAlt", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: inline-flex; align-items: center; justify-content: center;" }, ngImport: i0, template: `
188
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HugeiconsIconComponent, isStandalone: true, selector: "hugeicons-icon", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, altIcon: { classPropertyName: "altIcon", publicName: "altIcon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconClass: { classPropertyName: "iconClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, showAlt: { classPropertyName: "showAlt", publicName: "showAlt", isSignal: true, isRequired: false, transformFunction: null }, primaryColor: { classPropertyName: "primaryColor", publicName: "primaryColor", isSignal: true, isRequired: false, transformFunction: null }, secondaryColor: { classPropertyName: "secondaryColor", publicName: "secondaryColor", isSignal: true, isRequired: false, transformFunction: null }, disableSecondaryOpacity: { classPropertyName: "disableSecondaryOpacity", publicName: "disableSecondaryOpacity", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: inline-flex; align-items: center; justify-content: center;" }, ngImport: i0, template: `
39
189
  <svg
40
- [attr.width]="size()"
41
- [attr.height]="size()"
190
+ [attr.width]="resolvedSize()"
191
+ [attr.height]="resolvedSize()"
42
192
  viewBox="0 0 24 24"
43
193
  fill="none"
44
- [attr.color]="color()"
194
+ [attr.color]="mainColor()"
195
+ [attr.stroke]="strokeOverride()?.stroke"
196
+ [attr.stroke-width]="strokeOverride()?.strokeWidth"
45
197
  [class]="iconClass()"
46
198
  xmlns="http://www.w3.org/2000/svg"
47
- >
48
- @for (path of paths(); track $index) {
49
- <path
50
- [attr.d]="path.d"
51
- [attr.fill]="path.fill"
52
- [attr.opacity]="path.opacity"
53
- [attr.fill-rule]="path.fillRule"
54
- [attr.stroke]="path.stroke"
55
- [attr.stroke-width]="path.strokeWidth"
56
- />
57
- }
58
- </svg>
59
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
199
+ [hugeiconsSvgChildren]="paths()"
200
+ ></svg>
201
+ `, isInline: true, dependencies: [{ kind: "directive", type: HugeiconsSvgChildrenDirective, selector: "svg[hugeiconsSvgChildren]", inputs: ["hugeiconsSvgChildren"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
60
202
  }
61
203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HugeiconsIconComponent, decorators: [{
62
204
  type: Component,
63
205
  args: [{
64
- selector: 'hugeicons-icon',
206
+ selector: "hugeicons-icon",
65
207
  standalone: true,
208
+ imports: [HugeiconsSvgChildrenDirective],
66
209
  template: `
67
210
  <svg
68
- [attr.width]="size()"
69
- [attr.height]="size()"
211
+ [attr.width]="resolvedSize()"
212
+ [attr.height]="resolvedSize()"
70
213
  viewBox="0 0 24 24"
71
214
  fill="none"
72
- [attr.color]="color()"
215
+ [attr.color]="mainColor()"
216
+ [attr.stroke]="strokeOverride()?.stroke"
217
+ [attr.stroke-width]="strokeOverride()?.strokeWidth"
73
218
  [class]="iconClass()"
74
219
  xmlns="http://www.w3.org/2000/svg"
75
- >
76
- @for (path of paths(); track $index) {
77
- <path
78
- [attr.d]="path.d"
79
- [attr.fill]="path.fill"
80
- [attr.opacity]="path.opacity"
81
- [attr.fill-rule]="path.fillRule"
82
- [attr.stroke]="path.stroke"
83
- [attr.stroke-width]="path.strokeWidth"
84
- />
85
- }
86
- </svg>
220
+ [hugeiconsSvgChildren]="paths()"
221
+ ></svg>
87
222
  `,
88
223
  host: {
89
- style: 'display: inline-flex; align-items: center; justify-content: center;'
224
+ style: "display: inline-flex; align-items: center; justify-content: center;",
90
225
  },
91
- changeDetection: ChangeDetectionStrategy.OnPush
226
+ changeDetection: ChangeDetectionStrategy.OnPush,
92
227
  }]
93
228
  }] });
94
229
 
@@ -1 +1 @@
1
- {"version":3,"file":"hugeicons-angular.mjs","sources":["../../src/components/hugeicons-icon.component.ts","../../src/hugeicons-angular.ts"],"sourcesContent":["import { Component, ChangeDetectionStrategy, computed, input } from '@angular/core';\nimport { IconSvgObject } from '../lib/types';\n\ninterface PathData {\n d: string;\n fill: string;\n opacity?: string;\n fillRule?: string;\n stroke?: string;\n strokeWidth?: number;\n}\n\n@Component({\n selector: 'hugeicons-icon',\n standalone: true,\n template: `\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n [attr.color]=\"color()\"\n [class]=\"iconClass()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n @for (path of paths(); track $index) {\n <path\n [attr.d]=\"path.d\"\n [attr.fill]=\"path.fill\"\n [attr.opacity]=\"path.opacity\"\n [attr.fill-rule]=\"path.fillRule\"\n [attr.stroke]=\"path.stroke\"\n [attr.stroke-width]=\"path.strokeWidth\"\n />\n }\n </svg>\n `,\n host: {\n style: 'display: inline-flex; align-items: center; justify-content: center;'\n },\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class HugeiconsIconComponent {\n // Signal inputs - modern Angular 17.1+ approach\n readonly size = input<string | number>(24);\n readonly strokeWidth = input<number | undefined>(undefined);\n readonly absoluteStrokeWidth = input<boolean>(false);\n readonly icon = input.required<IconSvgObject>();\n readonly altIcon = input<IconSvgObject | undefined>(undefined);\n readonly color = input<string>('currentColor');\n readonly iconClass = input<string>('', { alias: 'class' });\n readonly showAlt = input<boolean>(false);\n\n // Computed signal for reactive path updates\n readonly paths = computed<PathData[]>(() => {\n const currentIcon = this.showAlt() && this.altIcon() ? this.altIcon()! : this.icon();\n\n if (!currentIcon || !Array.isArray(currentIcon)) {\n return [];\n }\n\n const strokeWidthValue = this.strokeWidth();\n const calculatedStrokeWidth = strokeWidthValue !== undefined\n ? (this.absoluteStrokeWidth() \n ? (Number(strokeWidthValue) * 24) / Number(this.size()) \n : strokeWidthValue)\n : undefined;\n\n const strokeProps = calculatedStrokeWidth !== undefined \n ? { strokeWidth: calculatedStrokeWidth, stroke: 'currentColor' } \n : {};\n\n return currentIcon.map(([_, attrs]) => ({\n d: attrs['d'],\n fill: attrs['fill'] || 'none',\n opacity: attrs['opacity'],\n fillRule: attrs['fillRule'],\n ...strokeProps\n }));\n });\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hugeicons-angular.mjs","sources":["../../src/lib/svg-attributes.ts","../../src/components/svg-children.directive.ts","../../src/components/hugeicons-icon.component.ts","../../src/hugeicons-angular.ts"],"sourcesContent":["/**\n * Maps the React-style prop names used by the icon data (strokeWidth, fillRule, xlinkHref …)\n * to real SVG attribute names, following the same rules as React DOM:\n * - names that SVG itself spells in camelCase (viewBox, gradientTransform …) are kept as-is\n * - xlink / xml prefixed names get their namespace\n * - every other camelCase name becomes kebab-case (strokeLinecap → stroke-linecap)\n * - names that are already kebab-case or lowercase pass through unchanged\n */\n\n/** SVG attributes whose canonical spelling is camelCase. */\nconst CAMEL_CASE_ATTRIBUTES = new Set([\n 'allowReorder', 'attributeName', 'attributeType', 'autoReverse', 'baseFrequency',\n 'baseProfile', 'calcMode', 'clipPathUnits', 'contentScriptType', 'contentStyleType',\n 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes', 'filterUnits',\n 'glyphRef', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength',\n 'keyPoints', 'keySplines', 'keyTimes', 'lengthAdjust', 'limitingConeAngle', 'markerHeight',\n 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength',\n 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX', 'pointsAtY',\n 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY',\n 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'specularConstant',\n 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles',\n 'surfaceScale', 'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength',\n 'viewBox', 'viewTarget', 'xChannelSelector', 'yChannelSelector', 'zoomAndPan',\n]);\n\n/** Namespaced attributes, as Renderer2 expects them: a namespace key plus the local name. */\nconst NAMESPACED_ATTRIBUTES: Record<string, { name: string; namespace: string }> = {\n xlinkActuate: { name: 'actuate', namespace: 'xlink' },\n xlinkArcrole: { name: 'arcrole', namespace: 'xlink' },\n xlinkHref: { name: 'href', namespace: 'xlink' },\n xlinkRole: { name: 'role', namespace: 'xlink' },\n xlinkShow: { name: 'show', namespace: 'xlink' },\n xlinkTitle: { name: 'title', namespace: 'xlink' },\n xlinkType: { name: 'type', namespace: 'xlink' },\n xmlBase: { name: 'base', namespace: 'xml' },\n xmlLang: { name: 'lang', namespace: 'xml' },\n xmlSpace: { name: 'space', namespace: 'xml' },\n xmlnsXlink: { name: 'xlink', namespace: 'xmlns' },\n};\n\n/** Props React consumes itself and never writes to the DOM. */\nconst IGNORED_PROPS = new Set(['key', 'ref', 'children', 'dangerouslySetInnerHTML']);\n\nexport interface SvgAttribute {\n /** Local attribute name */\n name: string;\n /** Renderer2 namespace key (xlink, xml, xmlns) or null */\n namespace: string | null;\n value: string;\n}\n\nexport function toSvgAttribute(prop: string, value: unknown): SvgAttribute | null {\n if (IGNORED_PROPS.has(prop) || value === undefined || value === null || value === false) {\n return null;\n }\n if (typeof value === 'function' || typeof value === 'object') {\n return null;\n }\n const stringValue = value === true ? '' : String(value);\n\n if (prop === 'className') {\n return { name: 'class', namespace: null, value: stringValue };\n }\n if (prop === 'htmlFor') {\n return { name: 'for', namespace: null, value: stringValue };\n }\n const namespaced = NAMESPACED_ATTRIBUTES[prop];\n if (namespaced) {\n return { name: namespaced.name, namespace: namespaced.namespace, value: stringValue };\n }\n if (CAMEL_CASE_ATTRIBUTES.has(prop) || !/[A-Z]/.test(prop)) {\n return { name: prop, namespace: null, value: stringValue };\n }\n return {\n name: prop.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`),\n namespace: null,\n value: stringValue,\n };\n}\n","import {\n Directive,\n ElementRef,\n Input,\n OnChanges,\n Renderer2,\n inject,\n} from \"@angular/core\";\nimport { toSvgAttribute } from \"../lib/svg-attributes\";\n\n/** One icon child: an SVG tag name plus React-style props. */\nexport interface SvgChildNode {\n tag: string;\n [prop: string]: unknown;\n}\n\n/**\n * Renders icon children into the host <svg>, with any tag and any attribute, the way\n * React's createElement does. A template can't bind a dynamic tag name, so the nodes\n * are built through Renderer2. It runs in ngOnChanges, i.e. synchronously during\n * change detection, so the icon is in the DOM right after detectChanges() and in\n * server-rendered HTML. Any children already present (e.g. from SSR) are replaced.\n */\n@Directive({\n selector: \"svg[hugeiconsSvgChildren]\",\n standalone: true,\n})\nexport class HugeiconsSvgChildrenDirective implements OnChanges {\n @Input({ required: true }) hugeiconsSvgChildren!: readonly SvgChildNode[];\n\n private readonly host: ElementRef<SVGSVGElement> = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n\n ngOnChanges(): void {\n const svg = this.host.nativeElement;\n\n // Iterate over a snapshot: with @angular/animations the renderer only queues the\n // removal until change detection ends, so svg.firstChild would never change.\n for (const child of Array.from(svg.childNodes)) {\n this.renderer.removeChild(svg, child);\n }\n\n for (const { tag, ...props } of this.hugeiconsSvgChildren ?? []) {\n const child = this.renderer.createElement(tag, \"svg\");\n for (const [prop, value] of Object.entries(props)) {\n const attribute = toSvgAttribute(prop, value);\n if (attribute) {\n this.renderer.setAttribute(\n child,\n attribute.name,\n attribute.value,\n attribute.namespace ?? undefined,\n );\n }\n }\n this.renderer.appendChild(svg, child);\n }\n }\n}\n","import {\n Component,\n ChangeDetectionStrategy,\n computed,\n input,\n} from \"@angular/core\";\nimport { IconSvgObject } from \"../lib/types\";\nimport { HugeiconsSvgChildrenDirective } from \"./svg-children.directive\";\n\n/**\n * One SVG child of an icon: the icon data's props (React-style camelCase names)\n * plus `tag`, the element name. The named fields are the ones 1.0.11 exposed.\n */\ninterface PathData {\n tag: string;\n d?: string;\n fill?: string;\n opacity?: string;\n fillRule?: string;\n stroke?: string;\n strokeWidth?: number | string;\n [prop: string]: unknown;\n}\n\n/**\n * 1.0.11 wrote fill=\"none\" on every child it rendered (always path, circle, ellipse or\n * rect). Kept for those tags so CSS such as `svg { fill: ... }` behaves as before;\n * any other tag is left untouched, like React.\n */\nconst LEGACY_FILL_NONE_TAGS = new Set([\"path\", \"circle\", \"ellipse\", \"rect\"]);\n\n@Component({\n selector: \"hugeicons-icon\",\n standalone: true,\n imports: [HugeiconsSvgChildrenDirective],\n template: `\n <svg\n [attr.width]=\"resolvedSize()\"\n [attr.height]=\"resolvedSize()\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n [attr.color]=\"mainColor()\"\n [attr.stroke]=\"strokeOverride()?.stroke\"\n [attr.stroke-width]=\"strokeOverride()?.strokeWidth\"\n [class]=\"iconClass()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n [hugeiconsSvgChildren]=\"paths()\"\n ></svg>\n `,\n host: {\n style:\n \"display: inline-flex; align-items: center; justify-content: center;\",\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class HugeiconsIconComponent {\n // Signal inputs - modern Angular 17.1+ approach\n readonly size = input<string | number>(24);\n readonly strokeWidth = input<number | undefined>(undefined);\n readonly absoluteStrokeWidth = input<boolean>(false);\n readonly icon = input.required<IconSvgObject>();\n readonly altIcon = input<IconSvgObject | undefined>(undefined);\n readonly color = input<string>(\"currentColor\");\n readonly iconClass = input<string>(\"\", { alias: \"class\" });\n readonly showAlt = input<boolean>(false);\n readonly primaryColor = input<string | undefined>(undefined);\n readonly secondaryColor = input<string | undefined>(undefined);\n readonly disableSecondaryOpacity = input<boolean>(false);\n\n // Like React's default props: an explicitly bound `undefined` still falls back to the default\n readonly resolvedSize = computed(() => this.size() ?? 24);\n readonly mainColor = computed(\n () => this.primaryColor() || (this.color() ?? \"currentColor\"),\n );\n\n /** Stroke width/color forced by the strokeWidth input, applied to the svg and every child. */\n readonly strokeOverride = computed(() => {\n const strokeWidthValue = this.strokeWidth();\n if (strokeWidthValue === undefined) {\n return undefined;\n }\n const strokeWidth = this.absoluteStrokeWidth()\n ? (Number(strokeWidthValue) * 24) / Number(this.resolvedSize())\n : strokeWidthValue;\n return { strokeWidth, stroke: \"currentColor\" };\n });\n\n // Computed signal for reactive path updates\n readonly paths = computed<PathData[]>(() => {\n const currentIcon =\n this.showAlt() && this.altIcon() ? this.altIcon()! : this.icon();\n\n if (!currentIcon || !Array.isArray(currentIcon)) {\n return [];\n }\n\n const strokeOverride = this.strokeOverride();\n const mainColor = this.mainColor();\n const secondaryColor = this.secondaryColor();\n const disableSecondaryOpacity = this.disableSecondaryOpacity();\n\n // Same ordering as @hugeicons/react: secondary (opacity) layers first\n return [...currentIcon]\n .sort(([, a], [, b]) => {\n const hasOpacityA = a[\"opacity\"] !== undefined;\n const hasOpacityB = b[\"opacity\"] !== undefined;\n return hasOpacityB ? 1 : hasOpacityA ? -1 : 0;\n })\n .map(([tag, rawAttrs]) => {\n const attrs = rawAttrs as Record<string, unknown>;\n const isSecondary = attrs[\"opacity\"] !== undefined;\n const colorProps = secondaryColor\n ? {\n [attrs[\"stroke\"] !== undefined ? \"stroke\" : \"fill\"]: isSecondary\n ? secondaryColor\n : mainColor,\n }\n : {};\n\n return {\n ...attrs,\n tag,\n fill:\n (attrs[\"fill\"] as string | undefined) ||\n (LEGACY_FILL_NONE_TAGS.has(tag) ? \"none\" : undefined),\n ...strokeOverride,\n ...colorProps,\n opacity:\n isSecondary && !disableSecondaryOpacity\n ? attrs[\"opacity\"]\n : undefined,\n } as PathData;\n });\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Maps the React-style prop names used by the icon data (strokeWidth, fillRule, xlinkHref …)
3
+ * to real SVG attribute names, following the same rules as React DOM:
4
+ * - names that SVG itself spells in camelCase (viewBox, gradientTransform …) are kept as-is
5
+ * - xlink / xml prefixed names get their namespace
6
+ * - every other camelCase name becomes kebab-case (strokeLinecap → stroke-linecap)
7
+ * - names that are already kebab-case or lowercase pass through unchanged
8
+ */
9
+ export interface SvgAttribute {
10
+ /** Local attribute name */
11
+ name: string;
12
+ /** Renderer2 namespace key (xlink, xml, xmlns) or null */
13
+ namespace: string | null;
14
+ value: string;
15
+ }
16
+ export declare function toSvgAttribute(prop: string, value: unknown): SvgAttribute | null;
@@ -40,4 +40,7 @@ export interface HugeiconsProps {
40
40
  color?: string;
41
41
  class?: string;
42
42
  showAlt?: boolean;
43
+ primaryColor?: string;
44
+ secondaryColor?: string;
45
+ disableSecondaryOpacity?: boolean;
43
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hugeicons/angular",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Hugeicons Angular Component Library https://hugeicons.com",
5
5
  "homepage": "https://hugeicons.com",
6
6
  "license": "MIT",
@@ -28,7 +28,7 @@
28
28
  "scripts": {
29
29
  "build": "pnpm clean && ng-packagr -p ng-package.json",
30
30
  "clean": "rm -rf dist",
31
- "test": "ng test",
31
+ "test": "pnpm build && node --test test/*.test.mjs",
32
32
  "publish:beta": "pnpm build && npm publish --tag beta --no-git-checks",
33
33
  "publish:prod": "pnpm build && npm publish --no-git-checks"
34
34
  },
@@ -40,11 +40,14 @@
40
40
  "@angular/core": ">=17.1.0 <23.0.0"
41
41
  },
42
42
  "devDependencies": {
43
+ "@angular/animations": "^17.0.0",
43
44
  "@angular/common": "^17.0.0",
44
45
  "@angular/compiler": "^17.0.0",
45
46
  "@angular/compiler-cli": "^17.0.0",
46
47
  "@angular/core": "^17.0.0",
48
+ "@angular/platform-browser": "^17.0.0",
47
49
  "@angular-devkit/build-angular": "^17.0.0",
50
+ "jsdom": "^24.1.3",
48
51
  "ng-packagr": "^17.0.0",
49
52
  "typescript": "~5.2.0"
50
53
  },