@leanix/components 0.4.511 → 0.4.512

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.
@@ -2593,6 +2593,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImpor
2593
2593
  }]
2594
2594
  }] });
2595
2595
 
2596
+ class DisplayAvatarsPipe {
2597
+ transform(users, type, size, userGroupWidth, autoScale, maxLength) {
2598
+ if (maxLength) {
2599
+ return users.slice(0, maxLength);
2600
+ }
2601
+ if (autoScale) {
2602
+ if (type === 'group') {
2603
+ const usersToShow = Math.floor((userGroupWidth - 2 * SIZES[size]) / ((SIZES[size] * 2) / 3)) + 1;
2604
+ return users.slice(0, usersToShow);
2605
+ }
2606
+ else {
2607
+ const usersToShow = Math.floor(userGroupWidth / (SIZES[size] + 2)) - 1;
2608
+ return users.slice(0, usersToShow);
2609
+ }
2610
+ }
2611
+ return users;
2612
+ }
2613
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: DisplayAvatarsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
2614
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.8", ngImport: i0, type: DisplayAvatarsPipe, isStandalone: true, name: "displayAvatars" }); }
2615
+ }
2616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: DisplayAvatarsPipe, decorators: [{
2617
+ type: Pipe,
2618
+ args: [{
2619
+ name: 'displayAvatars',
2620
+ standalone: true
2621
+ }]
2622
+ }] });
2623
+ const SIZES = {
2624
+ XS: 16,
2625
+ S: 24,
2626
+ M: 32,
2627
+ L: 40,
2628
+ XL: 64
2629
+ };
2630
+
2631
+ const IMAGE_READER = new InjectionToken('IMAGE_READER');
2632
+ const DEFAULT_IMAGE_ID = '00000000-0000-4000-0000-000000000001';
2633
+ const REFERENCE_SIZE_MAPPING = {
2634
+ XS: 16,
2635
+ S: 24,
2636
+ M: 32,
2637
+ L: 40,
2638
+ XL: 64
2639
+ };
2640
+ // We want to use 2x bigger images for avatars to support high resolution displays
2641
+ // So we want to draw them in their original size but use 2x the size as reference
2642
+ const AVATAR_SIZE_MAPPING = {
2643
+ XS: REFERENCE_SIZE_MAPPING.XS * 2,
2644
+ S: REFERENCE_SIZE_MAPPING.S * 2,
2645
+ M: REFERENCE_SIZE_MAPPING.M * 2,
2646
+ L: REFERENCE_SIZE_MAPPING.L * 2,
2647
+ XL: REFERENCE_SIZE_MAPPING.XL * 2
2648
+ };
2649
+ const AVATAR_COLORS = [
2650
+ '#00a399',
2651
+ '#0f7eb5',
2652
+ '#18aece',
2653
+ '#2889ff',
2654
+ '#ff914d',
2655
+ '#fad71e',
2656
+ '#fe6690',
2657
+ '#ab657a',
2658
+ '#916b50',
2659
+ '#9755cd',
2660
+ '#fc9785'
2661
+ ];
2662
+
2663
+ class AvatarComponent {
2664
+ constructor(imageReader) {
2665
+ this.imageReader = imageReader;
2666
+ this.size = 'M';
2667
+ this.showMailToLink = true;
2668
+ this.disabled = false;
2669
+ this.NAME = 'AvatarComponent';
2670
+ this.imageURL = this.imageReader.getAvatar(DEFAULT_IMAGE_ID, this.size, this.user?.displayName);
2671
+ }
2672
+ ngOnChanges(changes) {
2673
+ const { user } = changes;
2674
+ if (user && user.currentValue && !user.currentValue.technicalUser) {
2675
+ const { id, displayName } = this.user || {};
2676
+ this.imageURL = this.imageReader.getAvatar(id ?? undefined, this.size, displayName);
2677
+ }
2678
+ }
2679
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AvatarComponent, deps: [{ token: IMAGE_READER }], target: i0.ɵɵFactoryTarget.Component }); }
2680
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: AvatarComponent, isStandalone: true, selector: "lx-avatar", inputs: { user: "user", size: "size", showMailToLink: "showMailToLink", disabled: "disabled" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"imageURL | async; else loading\">\n <ng-container *ngIf=\"!user.technicalUser; else technicalUserIcon\">\n <a\n *ngIf=\"showMailToLink && user.email; else profilePicture\"\n class=\"userLink\"\n href=\"mailto:{{ user.email }}\"\n lxTooltip=\"{{ user.displayName }}\"\n >\n <img\n [src]=\"imageURL | async\"\n class=\"avatarImage\"\n [class]=\"size\"\n [class.disabled]=\"disabled\"\n role=\"presentation\"\n alt=\"{{ user.displayName }}\"\n />\n </a>\n <ng-template #profilePicture>\n <img\n [src]=\"imageURL | async\"\n class=\"avatarImage\"\n [class]=\"size\"\n [class.disabled]=\"disabled\"\n role=\"presentation\"\n alt=\"{{ user.displayName }}\"\n />\n </ng-template>\n </ng-container>\n <ng-template #technicalUserIcon>\n <i class=\"avatarImage fas fa-robot\" lxTooltip=\"{{ user.displayName }}\" [class]=\"size\" [class.disabled]=\"disabled\"></i>\n </ng-template>\n</ng-container>\n<ng-template #loading>\n <div class=\"avatarImage userLink loading\" [ngClass]=\"size\"></div>\n</ng-template>\n", styles: [".userLink{display:inline-block;width:fit-content;height:fit-content}.avatarImage{border-radius:50%}.avatarImage.disabled{opacity:.4}.loading{background:linear-gradient(270deg,#ccc,#eee,#ccc);background-size:200% 100%;animation:loading 1.5s infinite;object-fit:cover;vertical-align:middle}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.fa-robot{background-color:#b2bccc;color:#fff;vertical-align:middle;text-align:center}.fa-robot.XS{line-height:14px;font-size:10px}.fa-robot.S{line-height:22px;font-size:13px}.fa-robot.M{line-height:30px;font-size:18px}.fa-robot.L{line-height:38px;font-size:22px}.fa-robot.XL{line-height:62px;font-size:40px}.XS{width:16px;height:16px}.S{width:24px;height:24px}.M{width:32px;height:32px}.L{width:40px;height:40px}.XL{width:64px;height:64px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TooltipDirective, selector: "[lxTooltip]", inputs: ["lxTooltip", "lxTooltipPosition", "lxTooltipDelay", "lxTooltipIsHtmlContent"] }] }); }
2681
+ }
2682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AvatarComponent, decorators: [{
2683
+ type: Component,
2684
+ args: [{ selector: 'lx-avatar', standalone: true, imports: [NgIf, AsyncPipe, NgClass, TooltipDirective], template: "<ng-container *ngIf=\"imageURL | async; else loading\">\n <ng-container *ngIf=\"!user.technicalUser; else technicalUserIcon\">\n <a\n *ngIf=\"showMailToLink && user.email; else profilePicture\"\n class=\"userLink\"\n href=\"mailto:{{ user.email }}\"\n lxTooltip=\"{{ user.displayName }}\"\n >\n <img\n [src]=\"imageURL | async\"\n class=\"avatarImage\"\n [class]=\"size\"\n [class.disabled]=\"disabled\"\n role=\"presentation\"\n alt=\"{{ user.displayName }}\"\n />\n </a>\n <ng-template #profilePicture>\n <img\n [src]=\"imageURL | async\"\n class=\"avatarImage\"\n [class]=\"size\"\n [class.disabled]=\"disabled\"\n role=\"presentation\"\n alt=\"{{ user.displayName }}\"\n />\n </ng-template>\n </ng-container>\n <ng-template #technicalUserIcon>\n <i class=\"avatarImage fas fa-robot\" lxTooltip=\"{{ user.displayName }}\" [class]=\"size\" [class.disabled]=\"disabled\"></i>\n </ng-template>\n</ng-container>\n<ng-template #loading>\n <div class=\"avatarImage userLink loading\" [ngClass]=\"size\"></div>\n</ng-template>\n", styles: [".userLink{display:inline-block;width:fit-content;height:fit-content}.avatarImage{border-radius:50%}.avatarImage.disabled{opacity:.4}.loading{background:linear-gradient(270deg,#ccc,#eee,#ccc);background-size:200% 100%;animation:loading 1.5s infinite;object-fit:cover;vertical-align:middle}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.fa-robot{background-color:#b2bccc;color:#fff;vertical-align:middle;text-align:center}.fa-robot.XS{line-height:14px;font-size:10px}.fa-robot.S{line-height:22px;font-size:13px}.fa-robot.M{line-height:30px;font-size:18px}.fa-robot.L{line-height:38px;font-size:22px}.fa-robot.XL{line-height:62px;font-size:40px}.XS{width:16px;height:16px}.S{width:24px;height:24px}.M{width:32px;height:32px}.L{width:40px;height:40px}.XL{width:64px;height:64px}\n"] }]
2685
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
2686
+ type: Inject,
2687
+ args: [IMAGE_READER]
2688
+ }] }], propDecorators: { user: [{
2689
+ type: Input
2690
+ }], size: [{
2691
+ type: Input
2692
+ }], showMailToLink: [{
2693
+ type: Input
2694
+ }], disabled: [{
2695
+ type: Input
2696
+ }] } });
2697
+
2698
+ class AvatarGroupComponent {
2699
+ get userNames() {
2700
+ return this.users
2701
+ .map(({ displayName }) => displayName)
2702
+ .sort()
2703
+ .join('<br>');
2704
+ }
2705
+ constructor(cdr, zone) {
2706
+ this.cdr = cdr;
2707
+ this.zone = zone;
2708
+ this.NAME = 'AvatarGroupComponent';
2709
+ this.users = [];
2710
+ this.size = 'M';
2711
+ this.type = 'group';
2712
+ this.maxLength = 0;
2713
+ this.autoScale = false;
2714
+ this.disabledUserIds = [];
2715
+ this.overlayVisible = false;
2716
+ this.resizeObserver = new ResizeObserver(() => {
2717
+ this.zone.runOutsideAngular(() => {
2718
+ this.zone.run(() => {
2719
+ this.cdr.detectChanges();
2720
+ });
2721
+ });
2722
+ });
2723
+ }
2724
+ ngAfterViewInit() {
2725
+ this.resizeObserver.observe(this.userGroupElement.nativeElement);
2726
+ }
2727
+ handleClick(event) {
2728
+ event.stopPropagation();
2729
+ this.overlayVisible = true;
2730
+ }
2731
+ ngOnDestroy() {
2732
+ if (this.resizeObserver && this.userGroupElement) {
2733
+ this.resizeObserver.unobserve(this.userGroupElement.nativeElement);
2734
+ }
2735
+ }
2736
+ isUserDisabled(user) {
2737
+ return !!user.id && this.disabledUserIds.includes(user.id);
2738
+ }
2739
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AvatarGroupComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
2740
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: AvatarGroupComponent, isStandalone: true, selector: "lx-avatar-group", inputs: { title: "title", users: "users", size: "size", type: "type", maxLength: "maxLength", autoScale: "autoScale", disabledUserIds: "disabledUserIds" }, viewQueries: [{ propertyName: "userGroupElement", first: true, predicate: ["userGroup"], descendants: true }], ngImport: i0, template: "<div\n #userGroup\n (click)=\"handleClick($event)\"\n (keydown.enter)=\"handleClick($event)\"\n (keydown.space)=\"handleClick($event)\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n [lxTooltip]=\"!overlayVisible ? userNames : null\"\n [lxTooltipIsHtmlContent]=\"true\"\n tabindex=\"0\"\n role=\"button\"\n aria-haspopup=\"dialog\"\n>\n <div *ngIf=\"users | displayAvatars: type : size : userGroup.offsetWidth : autoScale : maxLength as filteredUsers\" class=\"group-container\">\n <lx-avatar\n [user]=\"user\"\n [size]=\"size\"\n [showMailToLink]=\"false\"\n [disabled]=\"isUserDisabled(user)\"\n [ngClass]=\"[type === 'individual' ? 'individual' : 'group', size]\"\n *ngFor=\"let user of filteredUsers\"\n />\n <div\n *ngIf=\"filteredUsers.length < users.length\"\n [ngClass]=\"[type === 'individual' ? 'individual' : 'group', size]\"\n class=\"more-users-icon\"\n >\n +{{ users.length - filteredUsers.length }}\n </div>\n </div>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"overlayVisible\"\n (overlayOutsideClick)=\"overlayVisible = false\"\n>\n <div class=\"avatars-overlay\">\n <div *ngIf=\"title\" class=\"avatars-overlay-title\">{{ title }}</div>\n <div class=\"avatars-list\">\n <div *ngFor=\"let user of users\" class=\"individual\">\n <lx-avatar [user]=\"user\" [size]=\"size\" [showMailToLink]=\"true\" [disabled]=\"isUserDisabled(user)\" />\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".group-container{display:flex;align-items:center}.group-container lx-avatar{display:flex;align-items:center}.group-container .more-users-icon{color:#61779d;background-color:#fff;border:1px solid #c2c9d6;border-radius:50%;font-weight:700;-webkit-user-select:none;user-select:none}.individual{margin-right:2px!important}.avatars-overlay{max-width:360px;overflow:auto;margin-top:5px;border-radius:10px;background-color:#fff;border:1px solid #c2c9d6;box-shadow:0 6px 12px #0000002d}.avatars-overlay .avatars-list{display:flex;flex-wrap:wrap;padding:10px}.avatars-overlay .avatars-list lx-avatar{display:block;margin-bottom:5px}.avatars-overlay .avatars-overlay-title{border-bottom:1px solid #c2c9d6;padding:10px;font-weight:700}.XS{width:16px;height:16px;line-height:16px;font-size:8px}.XS.group:not(:first-child){margin-left:-8px}.S{width:24px;height:24px;line-height:24px;font-size:11.25px}.S.group:not(:first-child){margin-left:-12px}.M{width:32px;height:32px;line-height:32px;text-align:center;vertical-align:middle;font-size:15.5px}.M.group:not(:first-child){margin-left:-10px}.L{width:40px;height:40px;line-height:40px;text-align:center;vertical-align:middle;font-size:large}.L.group:not(:first-child){margin-left:-20px}.XL{width:64px;height:64px;line-height:64px;text-align:center;vertical-align:middle;font-size:large}.XL.group:not(:first-child){margin-left:-50px}\n"], dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: TooltipDirective, selector: "[lxTooltip]", inputs: ["lxTooltip", "lxTooltipPosition", "lxTooltipDelay", "lxTooltipIsHtmlContent"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: AvatarComponent, selector: "lx-avatar", inputs: ["user", "size", "showMailToLink", "disabled"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "pipe", type: DisplayAvatarsPipe, name: "displayAvatars" }] }); }
2741
+ }
2742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: AvatarGroupComponent, decorators: [{
2743
+ type: Component,
2744
+ args: [{ selector: 'lx-avatar-group', standalone: true, imports: [CdkOverlayOrigin, TooltipDirective, NgIf, NgFor, AvatarComponent, NgClass, CdkConnectedOverlay, DisplayAvatarsPipe], template: "<div\n #userGroup\n (click)=\"handleClick($event)\"\n (keydown.enter)=\"handleClick($event)\"\n (keydown.space)=\"handleClick($event)\"\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n [lxTooltip]=\"!overlayVisible ? userNames : null\"\n [lxTooltipIsHtmlContent]=\"true\"\n tabindex=\"0\"\n role=\"button\"\n aria-haspopup=\"dialog\"\n>\n <div *ngIf=\"users | displayAvatars: type : size : userGroup.offsetWidth : autoScale : maxLength as filteredUsers\" class=\"group-container\">\n <lx-avatar\n [user]=\"user\"\n [size]=\"size\"\n [showMailToLink]=\"false\"\n [disabled]=\"isUserDisabled(user)\"\n [ngClass]=\"[type === 'individual' ? 'individual' : 'group', size]\"\n *ngFor=\"let user of filteredUsers\"\n />\n <div\n *ngIf=\"filteredUsers.length < users.length\"\n [ngClass]=\"[type === 'individual' ? 'individual' : 'group', size]\"\n class=\"more-users-icon\"\n >\n +{{ users.length - filteredUsers.length }}\n </div>\n </div>\n</div>\n\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"overlayVisible\"\n (overlayOutsideClick)=\"overlayVisible = false\"\n>\n <div class=\"avatars-overlay\">\n <div *ngIf=\"title\" class=\"avatars-overlay-title\">{{ title }}</div>\n <div class=\"avatars-list\">\n <div *ngFor=\"let user of users\" class=\"individual\">\n <lx-avatar [user]=\"user\" [size]=\"size\" [showMailToLink]=\"true\" [disabled]=\"isUserDisabled(user)\" />\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".group-container{display:flex;align-items:center}.group-container lx-avatar{display:flex;align-items:center}.group-container .more-users-icon{color:#61779d;background-color:#fff;border:1px solid #c2c9d6;border-radius:50%;font-weight:700;-webkit-user-select:none;user-select:none}.individual{margin-right:2px!important}.avatars-overlay{max-width:360px;overflow:auto;margin-top:5px;border-radius:10px;background-color:#fff;border:1px solid #c2c9d6;box-shadow:0 6px 12px #0000002d}.avatars-overlay .avatars-list{display:flex;flex-wrap:wrap;padding:10px}.avatars-overlay .avatars-list lx-avatar{display:block;margin-bottom:5px}.avatars-overlay .avatars-overlay-title{border-bottom:1px solid #c2c9d6;padding:10px;font-weight:700}.XS{width:16px;height:16px;line-height:16px;font-size:8px}.XS.group:not(:first-child){margin-left:-8px}.S{width:24px;height:24px;line-height:24px;font-size:11.25px}.S.group:not(:first-child){margin-left:-12px}.M{width:32px;height:32px;line-height:32px;text-align:center;vertical-align:middle;font-size:15.5px}.M.group:not(:first-child){margin-left:-10px}.L{width:40px;height:40px;line-height:40px;text-align:center;vertical-align:middle;font-size:large}.L.group:not(:first-child){margin-left:-20px}.XL{width:64px;height:64px;line-height:64px;text-align:center;vertical-align:middle;font-size:large}.XL.group:not(:first-child){margin-left:-50px}\n"] }]
2745
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { title: [{
2746
+ type: Input
2747
+ }], users: [{
2748
+ type: Input
2749
+ }], size: [{
2750
+ type: Input
2751
+ }], type: [{
2752
+ type: Input
2753
+ }], maxLength: [{
2754
+ type: Input
2755
+ }], autoScale: [{
2756
+ type: Input
2757
+ }], disabledUserIds: [{
2758
+ type: Input
2759
+ }], userGroupElement: [{
2760
+ type: ViewChild,
2761
+ args: ['userGroup']
2762
+ }] } });
2763
+
2596
2764
  /**
2597
2765
  * Skeleton is a component that can be used to show a loading state of a component.
2598
2766
  *
@@ -2827,6 +2995,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImpor
2827
2995
  args: [SatPopoverComponent]
2828
2996
  }] } });
2829
2997
 
2998
+ /**
2999
+ * Generates an SVG for the avatar initials
3000
+ * @param displayName The name of the user
3001
+ * @param size The size of the avatar
3002
+ * @returns A promise with the data URL of the generated SVG
3003
+ */
3004
+ function getInitialsUrl(displayName, size) {
3005
+ const twoWordsName = displayName.split(' ').slice(0, 2);
3006
+ const initials = twoWordsName.length === 1 ? `${twoWordsName[0]?.[0]}` : `${twoWordsName[0]?.[0]}${twoWordsName[1]?.[0]}`;
3007
+ const svg = generateInitialsSVG(initials.toUpperCase(), size && AVATAR_SIZE_MAPPING[size]);
3008
+ const blob = new Blob([svg], { type: 'image/svg+xml' });
3009
+ return blobToDataURL(blob);
3010
+ }
3011
+ function hashString(s) {
3012
+ let hash = 0;
3013
+ let i = 0;
3014
+ const l = s.length;
3015
+ if (l > 0)
3016
+ while (i < l)
3017
+ hash = ((hash << 5) - hash + s.charCodeAt(i++)) | 0;
3018
+ return Math.abs(hash);
3019
+ }
3020
+ function getAvatarColorHex(initials) {
3021
+ const tagNameHash = hashString(initials.toUpperCase());
3022
+ return AVATAR_COLORS[(tagNameHash % 11) + 1];
3023
+ }
3024
+ function generateInitialsSVG(initials, size = 24) {
3025
+ const fontSize = (size * 40) / 100;
3026
+ const textY = (size * 63) / 100;
3027
+ const svgTemplate = `
3028
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}" preserveAspectRatio="xMidYMid meet">
3029
+ <circle cx="${size / 2}" cy="${size / 2}" r="${size / 2}" fill="${getAvatarColorHex(initials)}"></circle>
3030
+ <text x="${size / 2}" y="${textY}" font-family="Arial" font-size="${fontSize}" text-anchor="middle" fill="#ffffff" style="user-select:none;-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none;">
3031
+ ${initials}
3032
+ </text>
3033
+ </svg>`;
3034
+ return svgTemplate;
3035
+ }
3036
+ function blobToDataURL(blob) {
3037
+ return new Promise((resolve, reject) => {
3038
+ const reader = new FileReader();
3039
+ reader.onload = (_e) => resolve(reader.result);
3040
+ reader.onerror = (_e) => reject(reader.error);
3041
+ reader.onabort = (_e) => reject(new Error('Read aborted'));
3042
+ reader.readAsDataURL(blob);
3043
+ });
3044
+ }
3045
+
2830
3046
  const defaultElement = 'span';
2831
3047
  const defaultClassName = 'highlight';
2832
3048
  /**
@@ -10135,5 +10351,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImpor
10135
10351
  * Generated bundle index. Do not edit.
10136
10352
  */
10137
10353
 
10138
- export { ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, AfterViewInitDirective, AutocloseDirective, AutocloseGroupService, AutofocusDirective, BACKSPACE, BadgeComponent, BannerComponent, BaseSelectDirective, BasicDropdownComponent, BasicDropdownItemComponent, BrPipe, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CORE_MODULE_EXPORTS, CURRENCY_SYMBOL_MAP, CardComponent, CdkOptionsDropdownComponent, CdkOptionsSubDropdownComponent, CollapsibleComponent, ContenteditableDirective, ContrastColorPipe, CounterComponent, CurrencyInputComponent, CurrencySymbolComponent, CustomDatePipe, DATEPICKER_CONTROL_VALUE_ACCESSOR, DATE_FN_LOCALE, DATE_FORMATS, DateFormatter, DateInputComponent, DatePickerComponent, DatepickerConfig, DatepickerUiModule, DragAndDropListComponent, DragAndDropListItemComponent, END, ENTER, ESCAPE, EllipsisComponent, EmptyStateComponent, ErrorMessageComponent, ExpandedDropdownComponent, FORMS_MODULE_EXPORTS, FORM_CONTROL_ERROR_DISPLAY_STRATEGY, FORM_CONTROL_ERROR_NAMESPACE, FilterSelectionPipe, FilterTermPipe, FormErrorComponent, FormErrorDirective, FormSubmitDirective, FormatNumberPipe, GLOBAL_TRANSLATION_OPTIONS, HOME, HighlightRangePipe, HighlightTermPipe, ICON_MAP, IconComponent, IconScaleComponent, InputComponent, KeyboardActionSourceDirective, KeyboardSelectAction, KeyboardSelectDirective, LOCALE_FN, LX_BUTTON_USE_SAP_ICONS, LX_ELLIPSIS_DEBOUNCE_ON_RESIZE, LxCoreUiModule, LxDragAndDropListModule, LxFormsModule, LxIsUuidPipe, LxLinkifyPipe, LxModalModule, LxPopoverUiModule, LxTabUiModule, LxTimeAgo, LxTranslatePipe, LxUnlinkifyPipe, MODAL_CLOSE, MODAL_MODULE_EXPORTS, MarkInvalidDirective, MarkdownPipe, MaxLengthCounterDirective, ModalCloseClickLocation, ModalComponent, ModalContentDirective, ModalFooterComponent, ModalHeaderComponent, MultiSelectComponent, NbspPipe, OptionComponent, OptionGroupComponent, OptionGroupDropdownComponent, OptionsDropdownComponent, OptionsSubDropdownComponent, PickerComponent, PickerOptionComponent, PickerTriggerDirective, PillItemComponent, PillListComponent, PopoverClickDirective, PopoverComponent, PopoverContentDirective, PopoverHoverDirective, RELEVANCE_SORTING_KEY, ResizeObserverService, ResponsiveInputComponent, SPACE, SelectDropdownDirective, SelectListComponent, SelectableItemDirective, SelectedOptionDirective, SingleSelectComponent, SkeletonComponent, SortPipe, Sorting, SortingDropdownComponent, SortingDropdownTriggerComponent, SpinnerComponent, StepperComponent, SwitchComponent, TAB, TabComponent, TabGroupComponent, TableComponent, TableHeaderComponent, TinySpinnerComponent, TokenComponent, TokenizerComponent, TokenizerOverflowPopoverComponent, TooltipComponent, TooltipDirective, TranslationAfterPipe, TranslationBeforePipe, TranslationBetweenPipe, UnescapeCurlyBracesPipe, ValidateDateInForeseeableFuture, ValidateStringNotInArray, ValidateStringNotInArrayAsync, getContrastColor, getTranslationParts, highlightText, isValidHexColor, isValidX, isValidY, provideFormControlErrorDisplayStrategy, provideFormControlErrorNamespace, shorthandHexHandle };
10354
+ export { ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, AVATAR_COLORS, AVATAR_SIZE_MAPPING, AfterViewInitDirective, AutocloseDirective, AutocloseGroupService, AutofocusDirective, AvatarComponent, AvatarGroupComponent, BACKSPACE, BadgeComponent, BannerComponent, BaseSelectDirective, BasicDropdownComponent, BasicDropdownItemComponent, BrPipe, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CORE_MODULE_EXPORTS, CURRENCY_SYMBOL_MAP, CardComponent, CdkOptionsDropdownComponent, CdkOptionsSubDropdownComponent, CollapsibleComponent, ContenteditableDirective, ContrastColorPipe, CounterComponent, CurrencyInputComponent, CurrencySymbolComponent, CustomDatePipe, DATEPICKER_CONTROL_VALUE_ACCESSOR, DATE_FN_LOCALE, DATE_FORMATS, DEFAULT_IMAGE_ID, DateFormatter, DateInputComponent, DatePickerComponent, DatepickerConfig, DatepickerUiModule, DragAndDropListComponent, DragAndDropListItemComponent, END, ENTER, ESCAPE, EllipsisComponent, EmptyStateComponent, ErrorMessageComponent, ExpandedDropdownComponent, FORMS_MODULE_EXPORTS, FORM_CONTROL_ERROR_DISPLAY_STRATEGY, FORM_CONTROL_ERROR_NAMESPACE, FilterSelectionPipe, FilterTermPipe, FormErrorComponent, FormErrorDirective, FormSubmitDirective, FormatNumberPipe, GLOBAL_TRANSLATION_OPTIONS, HOME, HighlightRangePipe, HighlightTermPipe, ICON_MAP, IMAGE_READER, IconComponent, IconScaleComponent, InputComponent, KeyboardActionSourceDirective, KeyboardSelectAction, KeyboardSelectDirective, LOCALE_FN, LX_BUTTON_USE_SAP_ICONS, LX_ELLIPSIS_DEBOUNCE_ON_RESIZE, LxCoreUiModule, LxDragAndDropListModule, LxFormsModule, LxIsUuidPipe, LxLinkifyPipe, LxModalModule, LxPopoverUiModule, LxTabUiModule, LxTimeAgo, LxTranslatePipe, LxUnlinkifyPipe, MODAL_CLOSE, MODAL_MODULE_EXPORTS, MarkInvalidDirective, MarkdownPipe, MaxLengthCounterDirective, ModalCloseClickLocation, ModalComponent, ModalContentDirective, ModalFooterComponent, ModalHeaderComponent, MultiSelectComponent, NbspPipe, OptionComponent, OptionGroupComponent, OptionGroupDropdownComponent, OptionsDropdownComponent, OptionsSubDropdownComponent, PickerComponent, PickerOptionComponent, PickerTriggerDirective, PillItemComponent, PillListComponent, PopoverClickDirective, PopoverComponent, PopoverContentDirective, PopoverHoverDirective, RELEVANCE_SORTING_KEY, ResizeObserverService, ResponsiveInputComponent, SPACE, SelectDropdownDirective, SelectListComponent, SelectableItemDirective, SelectedOptionDirective, SingleSelectComponent, SkeletonComponent, SortPipe, Sorting, SortingDropdownComponent, SortingDropdownTriggerComponent, SpinnerComponent, StepperComponent, SwitchComponent, TAB, TabComponent, TabGroupComponent, TableComponent, TableHeaderComponent, TinySpinnerComponent, TokenComponent, TokenizerComponent, TokenizerOverflowPopoverComponent, TooltipComponent, TooltipDirective, TranslationAfterPipe, TranslationBeforePipe, TranslationBetweenPipe, UnescapeCurlyBracesPipe, ValidateDateInForeseeableFuture, ValidateStringNotInArray, ValidateStringNotInArrayAsync, getContrastColor, getInitialsUrl, getTranslationParts, highlightText, isValidHexColor, isValidX, isValidY, provideFormControlErrorDisplayStrategy, provideFormControlErrorNamespace, shorthandHexHandle };
10139
10355
  //# sourceMappingURL=leanix-components.mjs.map