@frame-kit/ui-ng 0.2.24 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,15 @@ class AvatarComponent {
31
31
  if (!name) {
32
32
  return '?';
33
33
  }
34
- const parts = name.trim().split(/\s+/);
34
+ // Only words that start with a letter count, so a suffix such as
35
+ // "(she/her)" or "(dev)" never lends a bracket to the initials.
36
+ const parts = name
37
+ .trim()
38
+ .split(/\s+/)
39
+ .filter((part) => /^\p{L}/u.test(part));
40
+ if (parts.length === 0) {
41
+ return '?';
42
+ }
35
43
  if (parts.length >= 2) {
36
44
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
37
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-ui-avatar.mjs","sources":["../../../../packages/ui-ng/ui/avatar/avatar.component.ts","../../../../packages/ui-ng/ui/avatar/avatar.component.html","../../../../packages/ui-ng/ui/avatar/frame-kit-ui-ng-ui-avatar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport type { AvatarSize, AvatarStatus } from './avatar.types';\n\n@Component({\n selector: 'fk-avatar',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './avatar.component.html',\n styleUrl: './avatar.component.scss',\n})\nexport class AvatarComponent {\n // ===== IDENTITY =====\n /** Full display name used to derive initials when no explicit initials or image are provided. */\n readonly name = input.required<string>();\n /** URL of the avatar image; falls back to initials when the image fails to load. */\n readonly avatarUrl = input<string | null>(null);\n /** Explicit two-character initials that override the name-derived fallback. */\n readonly initials = input<string | null>(null);\n\n // ===== STATUS =====\n /** Online/offline/away status to reflect on the indicator dot. */\n readonly status = input<AvatarStatus | null>(null);\n /** When true, renders the status indicator dot over the avatar. */\n readonly showStatus = input<boolean>(false);\n\n // ===== DISPLAY =====\n /** Controls the avatar size. */\n readonly size = input<AvatarSize>('md');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n\n readonly derivedInitials = computed(() => {\n const explicit = this.initials();\n\n if (explicit) {\n return explicit;\n }\n\n const name = this.name();\n\n if (!name) {\n return '?';\n }\n\n const parts = name.trim().split(/\\s+/);\n\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n\n return parts[0].substring(0, 2).toUpperCase();\n });\n\n readonly showIndicator = computed(\n () => this.showStatus() && this.status() !== null,\n );\n\n readonly classes = computed(() => {\n return [\n 'fk-avatar',\n `fk-avatar--${this.size()}`,\n this.showIndicator() ? `fk-avatar--status-${this.status()}` : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n // Tracks whether the image failed to load\n readonly imgError = { value: false };\n\n onImgError(): void {\n this.imgError.value = true;\n }\n}\n","<!-- Avatar circle -->\n<span\n class=\"fk-avatar__circle\"\n [attr.aria-label]=\"ariaLabel() ?? 'Avatar for ' + name()\"\n role=\"img\"\n>\n @if (avatarUrl() && !imgError.value) {\n <img\n class=\"fk-avatar__image\"\n [src]=\"avatarUrl()\"\n [alt]=\"name()\"\n (error)=\"onImgError()\"\n />\n } @else {\n <span class=\"fk-avatar__initials\" aria-hidden=\"true\">\n {{ derivedInitials() }}\n </span>\n }\n</span>\n\n<!-- Status indicator -->\n@if (showIndicator()) {\n <span\n class=\"fk-avatar__status\"\n [attr.aria-label]=\"status() + ' status'\"\n role=\"status\"\n ></span>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame-kit-ui-ng-ui-avatar.mjs","sources":["../../../../packages/ui-ng/ui/avatar/avatar.component.ts","../../../../packages/ui-ng/ui/avatar/avatar.component.html","../../../../packages/ui-ng/ui/avatar/frame-kit-ui-ng-ui-avatar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport type { AvatarSize, AvatarStatus } from './avatar.types';\n\n@Component({\n selector: 'fk-avatar',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './avatar.component.html',\n styleUrl: './avatar.component.scss',\n})\nexport class AvatarComponent {\n // ===== IDENTITY =====\n /** Full display name used to derive initials when no explicit initials or image are provided. */\n readonly name = input.required<string>();\n /** URL of the avatar image; falls back to initials when the image fails to load. */\n readonly avatarUrl = input<string | null>(null);\n /** Explicit two-character initials that override the name-derived fallback. */\n readonly initials = input<string | null>(null);\n\n // ===== STATUS =====\n /** Online/offline/away status to reflect on the indicator dot. */\n readonly status = input<AvatarStatus | null>(null);\n /** When true, renders the status indicator dot over the avatar. */\n readonly showStatus = input<boolean>(false);\n\n // ===== DISPLAY =====\n /** Controls the avatar size. */\n readonly size = input<AvatarSize>('md');\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n\n readonly derivedInitials = computed(() => {\n const explicit = this.initials();\n\n if (explicit) {\n return explicit;\n }\n\n const name = this.name();\n\n if (!name) {\n return '?';\n }\n\n // Only words that start with a letter count, so a suffix such as\n // \"(she/her)\" or \"(dev)\" never lends a bracket to the initials.\n const parts = name\n .trim()\n .split(/\\s+/)\n .filter((part) => /^\\p{L}/u.test(part));\n\n if (parts.length === 0) {\n return '?';\n }\n\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n\n return parts[0].substring(0, 2).toUpperCase();\n });\n\n readonly showIndicator = computed(\n () => this.showStatus() && this.status() !== null,\n );\n\n readonly classes = computed(() => {\n return [\n 'fk-avatar',\n `fk-avatar--${this.size()}`,\n this.showIndicator() ? `fk-avatar--status-${this.status()}` : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n // Tracks whether the image failed to load\n readonly imgError = { value: false };\n\n onImgError(): void {\n this.imgError.value = true;\n }\n}\n","<!-- Avatar circle -->\n<span\n class=\"fk-avatar__circle\"\n [attr.aria-label]=\"ariaLabel() ?? 'Avatar for ' + name()\"\n role=\"img\"\n>\n @if (avatarUrl() && !imgError.value) {\n <img\n class=\"fk-avatar__image\"\n [src]=\"avatarUrl()\"\n [alt]=\"name()\"\n (error)=\"onImgError()\"\n />\n } @else {\n <span class=\"fk-avatar__initials\" aria-hidden=\"true\">\n {{ derivedInitials() }}\n </span>\n }\n</span>\n\n<!-- Status indicator -->\n@if (showIndicator()) {\n <span\n class=\"fk-avatar__status\"\n [attr.aria-label]=\"status() + ' status'\"\n role=\"status\"\n ></span>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frame-kit/ui-ng",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Style-agnostic, token-driven Angular UI component library for FrameKit.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,7 @@
17
17
  "@angular/forms": "^21.2.0",
18
18
  "@angular/platform-browser": "^21.2.0",
19
19
  "@angular/router": "^21.2.0",
20
- "@frame-kit/utils": "0.2.24",
20
+ "@frame-kit/utils": "0.2.25",
21
21
  "rxjs": "^7.0.0"
22
22
  },
23
23
  "sideEffects": false,
@@ -25,7 +25,7 @@ A token-driven avatar atom that displays a user image with an initials fallback
25
25
  ## Features
26
26
 
27
27
  - Displays an image when `avatarUrl` is provided, gracefully falling back to initials on load error
28
- - Auto-derives initials from `name` (first + last initial for multi-word names, first two characters for single names)
28
+ - Auto-derives initials from `name` (first + last initial for multi-word names, first two characters for single names); words that do not start with a letter, such as a "(she/her)" suffix, are ignored
29
29
  - Status indicator dot positioned at the bottom-right corner, color-coded by status
30
30
  - Three size presets (`sm`, `md`, `lg`) controlled via tokens
31
31
  - Fully token-driven — all colors, sizes, typography, and radii are overridable