@marianmeres/stuic 2.53.0 → 2.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,10 @@
1
1
  <script lang="ts" module>
2
2
  export type IconFn = (opts?: { size?: number; class?: string }) => string;
3
- export type AvatarFallback = "icon" | "initials" | { icon: IconFn } | { initials: string };
3
+ export type AvatarFallback =
4
+ | "icon"
5
+ | "initials"
6
+ | { icon: IconFn }
7
+ | { initials: string };
4
8
 
5
9
  export interface Props {
6
10
  /** Photo URL - when provided, renders in photo mode */
@@ -9,6 +13,8 @@
9
13
  alt?: string;
10
14
  /** String to extract initials from. Supports: "AB", "John Doe", or "john.doe@example.com" */
11
15
  initials?: string;
16
+ /** optional length */
17
+ initialsLength?: number;
12
18
  /** Icon function to display - when provided alone, renders in icon mode */
13
19
  icon?: IconFn;
14
20
  /** Fallback when photo fails to load. Defaults to "icon" */
@@ -41,6 +47,7 @@
41
47
  src,
42
48
  alt,
43
49
  initials: initialsProp,
50
+ initialsLength = 2,
44
51
  icon,
45
52
  fallback = "icon",
46
53
  hashSource,
@@ -60,26 +67,14 @@
60
67
  xl: { container: "size-16 text-lg", icon: 32 },
61
68
  };
62
69
 
63
- // Image loading state
64
- let imageError = $state(false);
65
-
66
- // Reset image state when src changes
67
- $effect(() => {
68
- if (src) {
69
- imageError = false;
70
- }
71
- });
72
-
73
- // Extract initials from string
74
- let extractedInitials = $derived.by(() => {
75
- let _input = (initialsProp || "").trim();
76
-
70
+ // Extract initials from input string (email, name, or raw initials)
71
+ function extractInitials(input: string, length: number): string {
72
+ let _input = (input || "").trim();
77
73
  if (!_input) return "?";
78
74
 
79
- // Check if input looks like an email
75
+ // Email handling
80
76
  if (_input.includes("@")) {
81
77
  const username = _input.split("@")[0];
82
- // Split by common separators (., _, -)
83
78
  const parts = username.split(/[._+-]/).filter(Boolean);
84
79
  if (parts.length > 1) {
85
80
  _input = parts.map((p) => p.charAt(0)).join("");
@@ -87,8 +82,8 @@
87
82
  _input = username;
88
83
  }
89
84
  }
90
- // Check if input looks like a full name (multiple words)
91
- else if (_input.length > 2 && /\s/.test(_input)) {
85
+ // Full name handling
86
+ else if (_input.length > length && /\s/.test(_input)) {
92
87
  _input = _input
93
88
  .split(/\s/)
94
89
  .map((v) => v.trim())
@@ -97,10 +92,21 @@
97
92
  .join("");
98
93
  }
99
94
 
100
- // Extract first 2 chars, uppercase
101
- return _input.slice(0, 2).toUpperCase();
95
+ return _input.slice(0, length).toUpperCase();
96
+ }
97
+
98
+ // Image loading state
99
+ let imageError = $state(false);
100
+
101
+ // Reset image state when src changes
102
+ $effect(() => {
103
+ if (src) {
104
+ imageError = false;
105
+ }
102
106
  });
103
107
 
108
+ let extractedInitials = $derived(extractInitials(initialsProp || "", initialsLength));
109
+
104
110
  // Determine the current render mode
105
111
  let renderMode = $derived.by((): "photo" | "initials" | "icon" => {
106
112
  // Photo mode (if src provided and no error)
@@ -121,28 +127,7 @@
121
127
  // Get fallback initials (from fallback prop or initialsProp)
122
128
  let fallbackInitials = $derived.by(() => {
123
129
  if (typeof fallback === "object" && "initials" in fallback) {
124
- const _input = (fallback.initials || "").trim();
125
- if (!_input) return "?";
126
-
127
- // Apply same extraction logic
128
- let result = _input;
129
- if (_input.includes("@")) {
130
- const username = _input.split("@")[0];
131
- const parts = username.split(/[._+-]/).filter(Boolean);
132
- if (parts.length > 1) {
133
- result = parts.map((p) => p.charAt(0)).join("");
134
- } else {
135
- result = username;
136
- }
137
- } else if (_input.length > 2 && /\s/.test(_input)) {
138
- result = _input
139
- .split(/\s/)
140
- .map((v) => v.trim())
141
- .filter(Boolean)
142
- .map((v) => v.charAt(0))
143
- .join("");
144
- }
145
- return result.slice(0, 2).toUpperCase();
130
+ return extractInitials(fallback.initials || "", initialsLength);
146
131
  }
147
132
  return extractedInitials;
148
133
  });
@@ -207,12 +192,7 @@
207
192
  {#if onclick}
208
193
  <button bind:this={el} type="button" class={baseClass} {style} {onclick}>
209
194
  {#if renderMode === "photo"}
210
- <img
211
- {src}
212
- {alt}
213
- class="size-full object-cover"
214
- onerror={handleImageError}
215
- />
195
+ <img {src} {alt} class="size-full object-cover" onerror={handleImageError} />
216
196
  {:else if renderMode === "initials"}
217
197
  {fallbackInitials}
218
198
  {:else}
@@ -222,12 +202,7 @@
222
202
  {:else}
223
203
  <div bind:this={el} class={baseClass} {style}>
224
204
  {#if renderMode === "photo"}
225
- <img
226
- {src}
227
- {alt}
228
- class="size-full object-cover"
229
- onerror={handleImageError}
230
- />
205
+ <img {src} {alt} class="size-full object-cover" onerror={handleImageError} />
231
206
  {:else if renderMode === "initials"}
232
207
  {fallbackInitials}
233
208
  {:else}
@@ -14,6 +14,8 @@ export interface Props {
14
14
  alt?: string;
15
15
  /** String to extract initials from. Supports: "AB", "John Doe", or "john.doe@example.com" */
16
16
  initials?: string;
17
+ /** optional length */
18
+ initialsLength?: number;
17
19
  /** Icon function to display - when provided alone, renders in icon mode */
18
20
  icon?: IconFn;
19
21
  /** Fallback when photo fails to load. Defaults to "icon" */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "2.53.0",
3
+ "version": "2.54.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",