@grasco/profile-picture 0.1.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.
@@ -0,0 +1,353 @@
1
+ 'use strict';var lit=require('lit'),decorators_js=require('lit/decorators.js'),styleMap_js=require('lit/directives/style-map.js');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var H=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var a=(t,r,e,n)=>{for(var i=n>1?void 0:n?W(r,e):r,p=t.length-1,l;p>=0;p--)(l=t[p])&&(i=(n?l(r,e,i):l(i))||i);return n&&i&&H(r,e,i),i};var C="grasco-profile-picture-styles",x=false;function k(){if(x||typeof document>"u")return;if(document.getElementById(C)){x=true;return}if(document.querySelector('link[href*="profile-picture"][href$="styles.css"]')){x=true;return}let r=Y();if(!r)return;let e=document.createElement("link");e.id=C,e.rel="stylesheet",e.href=r,document.head.appendChild(e),x=true;}function Y(){if(typeof window<"u"&&window.__GRASCO_PROFILE_PICTURE_CSS__)return window.__GRASCO_PROFILE_PICTURE_CSS__;try{let r=(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('angular.cjs', document.baseURI).href));if(r)return `${r.substring(0,r.lastIndexOf("/")+1)}styles.css`}catch{}let t=document.currentScript;if(t?.src){let r=new URL(t.src);return `${r.href.substring(0,r.href.lastIndexOf("/")+1)}styles.css`}return null}var w={"2xs":20,xs:24,sm:32,md:40,lg:48,xl:64,"2xl":80,"3xl":120},z={online:"#30D158",away:"#FFD60A",busy:"#FF453A",offline:"#8E8E93",dnd:"#FF453A"},$={none:"none",sm:"0 1px 2px 0 rgba(0, 0, 0, 0.05)",md:"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",lg:"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",glow:"0 0 20px 0 rgba(99, 102, 241, 0.3)"},c={size:"md",variant:"circle",loading:"lazy",placeholder:"shimmer",borderWidth:2,borderColor:"#ffffff",placeholderColor:"#f3f4f6",shadow:"sm"};var m={circle:"9999px",rounded:"12px",squircle:"30%",square:"0px"};function f(...t){return t.filter(Boolean).join(" ")}function y(t){return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(t)}function R(t){return {"top-left":"np:top-0 np:left-0","top-right":"np:top-0 np:right-0","bottom-left":"np:bottom-0 np:left-0","bottom-right":"np:bottom-0 np:right-0"}[t]}function I(t){return {"top-left":"np:-rotate-45 np:-translate-x-1/4 np:-translate-y-1/2","top-right":"np:rotate-45 np:translate-x-1/4 np:-translate-y-1/2","bottom-left":"np:rotate-45 np:-translate-x-1/4 np:translate-y-1/2","bottom-right":"np:-rotate-45 np:translate-x-1/4 np:translate-y-1/2"}[t]}function A(t){let e=t.trim().replace(/[^\w\s]/g,"").split(/\s+/).filter(Boolean);return e.length===0?"?":e.length===1?e[0].slice(0,1).toUpperCase():(e[0][0]+e[e.length-1][0]).toUpperCase()}function S(t){return Math.round(t*.38)}function E(t,r){let n=Math.max(r?18:10,Math.round(t*(r?.32:.22))),i=Math.round(n*.6);return {size:n,fontSize:i}}function M(t,r){return Math.max(8,Math.round(t*.25))+(r-1)*2}function L(t,r){return typeof t=="string"?t:r&&t>r?`${r}+`:t.toString()}function D(t){return t.length===0?"transparent":t.length===1?t[0]:`conic-gradient(${t.map((e,n)=>{let i=n/t.length*360,p=(n+1)/t.length*360;return `${e} ${i}deg ${p}deg`}).join(", ")})`}function q(t){let r=0;for(let e=0;e<t.length;e++){let n=t.charCodeAt(e);r=(r<<5)-r+n,r&=r;}return Math.abs(r)}function F(t){let r=["linear-gradient(135deg, #667eea 0%, #764ba2 100%)","linear-gradient(135deg, #f093fb 0%, #f5576c 100%)","linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)","linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)","linear-gradient(135deg, #fa709a 0%, #fee140 100%)","linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)","linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)","linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)","linear-gradient(135deg, #cd9cf2 0%, #f6f3ff 100%)","linear-gradient(135deg, #fddb92 0%, #d1fdff 100%)"],e=q(t)%r.length;return r[e]}function B(t){return {circle:"np:rounded-full",rounded:"np:rounded-xl",squircle:"np:rounded-[30%]",square:"np:rounded-none"}[t]}function T(t,r){return {className:{1:"np:border",2:"np:border-2",3:"np:border-[3px]",4:"np:border-4"}[t],style:{borderColor:r,borderStyle:"solid"}}}function G(t,r){return r?{className:"",style:{background:r}}:t?t.includes("gradient")?{className:"",style:{background:t}}:{className:"",style:{backgroundColor:t}}:{className:"np:bg-gray-100"}}function U(t){return {boxShadow:$[t]}}var Z={shimmer:`
2
+ @keyframes pp-shimmer {
3
+ 0% { transform: translateX(-100%); }
4
+ 100% { transform: translateX(100%); }
5
+ }`,pulse:`
6
+ @keyframes pp-pulse {
7
+ 0%, 100% { opacity: 1; transform: scale(1); }
8
+ 50% { opacity: 0.7; transform: scale(0.98); }
9
+ }`,skeleton:`
10
+ @keyframes pp-skeleton {
11
+ 0%, 100% { opacity: 1; }
12
+ 50% { opacity: 0.5; }
13
+ }`,badgeBounce:`
14
+ @keyframes pp-badge-bounce {
15
+ 0% { transform: scale(0) translateY(10px); opacity: 0; }
16
+ 50% { transform: scale(1.2) translateY(-2px); }
17
+ 100% { transform: scale(1) translateY(0); opacity: 1; }
18
+ }`,ringRotate:`
19
+ @keyframes pp-ring-rotate {
20
+ from { transform: rotate(0deg); }
21
+ to { transform: rotate(360deg); }
22
+ }`,presencePulse:`
23
+ @keyframes pp-presence-pulse {
24
+ 0%, 100% { box-shadow: 0 0 0 0 currentColor; }
25
+ 50% { box-shadow: 0 0 0 4px transparent; }
26
+ }`,glow:`
27
+ @keyframes pp-glow {
28
+ 0%, 100% { box-shadow: 0 0 20px 0 var(--pp-glow-color, rgba(99, 102, 241, 0.3)); }
29
+ 50% { box-shadow: 0 0 30px 5px var(--pp-glow-color, rgba(99, 102, 241, 0.5)); }
30
+ }`,fadeIn:`
31
+ @keyframes pp-fade-in {
32
+ from { opacity: 0; }
33
+ to { opacity: 1; }
34
+ }`,scaleIn:`
35
+ @keyframes pp-scale-in {
36
+ 0% { transform: scale(0.8); opacity: 0; }
37
+ 50% { transform: scale(1.05); }
38
+ 100% { transform: scale(1); opacity: 1; }
39
+ }`},_=Object.values(Z).join(`
40
+ `),K=`
41
+ /* Profile Picture Component Styles */
42
+ .pp-container {
43
+ --pp-transition-duration: 200ms;
44
+ --pp-transition-timing: cubic-bezier(0.4, 0, 0.2, 1);
45
+ --pp-spring-timing: cubic-bezier(0.34, 1.56, 0.64, 1);
46
+ position: relative;
47
+ display: inline-flex;
48
+ align-items: center;
49
+ justify-content: center;
50
+ user-select: none;
51
+ -webkit-user-select: none;
52
+ flex-shrink: 0;
53
+ }
54
+
55
+ /* Inner container for image clipping - allows badges/rings to overflow */
56
+ .pp-inner {
57
+ position: absolute;
58
+ inset: 0;
59
+ overflow: hidden;
60
+ border-radius: inherit;
61
+ }
62
+
63
+ /* Interactive states */
64
+ .pp-interactive {
65
+ cursor: pointer;
66
+ transition: transform var(--pp-transition-duration) var(--pp-spring-timing),
67
+ box-shadow var(--pp-transition-duration) var(--pp-transition-timing);
68
+ }
69
+
70
+ .pp-interactive:hover {
71
+ transform: scale(1.05);
72
+ }
73
+
74
+ .pp-interactive:active {
75
+ transform: scale(0.95);
76
+ }
77
+
78
+ .pp-interactive:focus-visible {
79
+ outline: none;
80
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5);
81
+ }
82
+
83
+ /* Image styles */
84
+ .pp-image {
85
+ position: absolute;
86
+ inset: 0;
87
+ width: 100%;
88
+ height: 100%;
89
+ object-fit: cover;
90
+ transition: opacity var(--pp-transition-duration) var(--pp-transition-timing);
91
+ }
92
+
93
+ .pp-image-loading {
94
+ opacity: 0;
95
+ }
96
+
97
+ .pp-image-loaded {
98
+ opacity: 1;
99
+ }
100
+
101
+ /* Fallback styles */
102
+ .pp-fallback {
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ width: 100%;
107
+ height: 100%;
108
+ font-weight: 500;
109
+ color: rgba(255, 255, 255, 0.9);
110
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
111
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
112
+ letter-spacing: 0.02em;
113
+ }
114
+
115
+ .pp-fallback-icon {
116
+ color: rgba(156, 163, 175, 0.8);
117
+ }
118
+
119
+ /* Shimmer placeholder */
120
+ .pp-shimmer {
121
+ position: absolute;
122
+ inset: 0;
123
+ overflow: hidden;
124
+ }
125
+
126
+ .pp-shimmer::after {
127
+ content: '';
128
+ position: absolute;
129
+ inset: 0;
130
+ background: linear-gradient(
131
+ 90deg,
132
+ transparent 0%,
133
+ rgba(255, 255, 255, 0.4) 50%,
134
+ transparent 100%
135
+ );
136
+ animation: pp-shimmer 1.5s infinite;
137
+ }
138
+
139
+ /* Pulse placeholder */
140
+ .pp-pulse {
141
+ animation: pp-pulse 2s ease-in-out infinite;
142
+ }
143
+
144
+ /* Skeleton placeholder */
145
+ .pp-skeleton {
146
+ background: linear-gradient(90deg, #e5e7eb 0%, #f3f4f6 50%, #e5e7eb 100%);
147
+ background-size: 200% 100%;
148
+ animation: pp-skeleton 1.5s ease-in-out infinite;
149
+ }
150
+
151
+ /* Badge styles */
152
+ .pp-badge {
153
+ position: absolute;
154
+ display: flex;
155
+ align-items: center;
156
+ justify-content: center;
157
+ border-radius: 9999px;
158
+ font-weight: 600;
159
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;
160
+ line-height: 1;
161
+ animation: pp-badge-bounce 0.4s var(--pp-spring-timing);
162
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
163
+ border: 2px solid white;
164
+ }
165
+
166
+ .pp-badge-pulse {
167
+ animation: pp-badge-bounce 0.4s var(--pp-spring-timing),
168
+ pp-presence-pulse 2s ease-in-out infinite 0.4s;
169
+ }
170
+
171
+ .pp-badge-glow {
172
+ box-shadow: 0 0 10px 2px var(--pp-badge-glow-color, currentColor);
173
+ }
174
+
175
+ /* Ribbon styles */
176
+ .pp-ribbon-container {
177
+ position: absolute;
178
+ z-index: 10;
179
+ overflow: hidden;
180
+ }
181
+
182
+ .pp-ribbon {
183
+ position: absolute;
184
+ width: 100%;
185
+ text-align: center;
186
+ font-weight: 600;
187
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;
188
+ text-transform: uppercase;
189
+ letter-spacing: 0.05em;
190
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
191
+ }
192
+
193
+ /* Ring effect (Instagram-style) */
194
+ .pp-ring {
195
+ position: absolute;
196
+ inset: -4px;
197
+ border-radius: inherit;
198
+ padding: 3px;
199
+ background: var(--pp-ring-color, linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888));
200
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
201
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
202
+ -webkit-mask-composite: xor;
203
+ mask-composite: exclude;
204
+ }
205
+
206
+ .pp-ring-animated {
207
+ animation: pp-ring-rotate 3s linear infinite;
208
+ }
209
+
210
+ /* Presence indicator */
211
+ .pp-presence {
212
+ position: absolute;
213
+ bottom: 0;
214
+ right: 0;
215
+ border-radius: 9999px;
216
+ border: 2px solid white;
217
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
218
+ }
219
+
220
+ .pp-presence-animated {
221
+ animation: pp-presence-pulse 2s ease-in-out infinite;
222
+ }
223
+
224
+ /* Glow effect */
225
+ .pp-glow {
226
+ animation: pp-glow 2s ease-in-out infinite;
227
+ }
228
+
229
+ /* Reduced motion support */
230
+ @media (prefers-reduced-motion: reduce) {
231
+ .pp-container,
232
+ .pp-interactive,
233
+ .pp-image,
234
+ .pp-shimmer::after,
235
+ .pp-pulse,
236
+ .pp-skeleton,
237
+ .pp-badge,
238
+ .pp-ring-animated,
239
+ .pp-presence-animated,
240
+ .pp-glow {
241
+ animation: none !important;
242
+ transition: none !important;
243
+ }
244
+ }
245
+ `,O=`${_}
246
+ ${K}`,j=`
247
+ @keyframes np-shimmer {
248
+ 0% { background-position: -200% 0; }
249
+ 100% { background-position: 200% 0; }
250
+ }
251
+ .np-shimmer {
252
+ background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%);
253
+ background-size: 200% 100%;
254
+ animation: np-shimmer 1.5s infinite;
255
+ }
256
+ `;function N(t,r=.3){if(y(t)){let e=Number.parseInt(t.slice(1,3),16),n=Number.parseInt(t.slice(3,5),16),i=Number.parseInt(t.slice(5,7),16);return `0 0 20px 0 rgba(${e}, ${n}, ${i}, ${r})`}return `0 0 20px 0 ${t}`}var o=class extends lit.LitElement{constructor(){super(...arguments);this.src="";this.alt="";this.size=c.size;this.variant=c.variant;this.shadow=c.shadow;this.border=false;this.borderWidth=c.borderWidth;this.borderColor=c.borderColor;this.loading=c.loading;this.placeholder=c.placeholder;this.placeholderColor=c.placeholderColor;this.isLoaded=false;this.hasError=false;this.previousSrc="";}createRenderRoot(){return o.injectStylesOnce(),this}static injectStylesOnce(){if(o.stylesInjected||typeof document>"u")return;let e=document.createElement("style");e.textContent=O,document.head.appendChild(e),o.stylesInjected=true;}get pixelSize(){let e=this.size;return typeof e=="number"?e:w[e]??w[c.size]}willUpdate(e){e.has("src")&&this.src!==this.previousSrc&&(this.isLoaded=false,this.hasError=false,this.previousSrc=this.src);}handleLoad(){this.isLoaded=true,this.dispatchEvent(new CustomEvent("load",{bubbles:true,composed:true}));}handleError(){this.hasError=true,this.isLoaded=true,this.dispatchEvent(new CustomEvent("error",{bubbles:true,composed:true}));}getContainerStyles(){let e=G(this.bgColor,this.bgGradient),n=this.border?T(this.borderWidth,this.borderColor):null,i=U(this.shadow),p={};if(this.glow){let u=this.glow.color??this.borderColor??"#6366f1";p={"--pp-glow-color":u,boxShadow:N(u,this.glow.intensity??.3)};}let l=this.interactive?.hoverable||this.interactive?.pressable;return {classes:f("pp-container",B(this.variant),e.className,n?.className,l&&"pp-interactive",this.glow?.animate&&"pp-glow"),styles:{width:`${this.pixelSize}px`,height:`${this.pixelSize}px`,borderRadius:m[this.variant],...e.style,...n?.style,...i,...p,cursor:this.interactive?.cursor??(l?"pointer":"default")}}}renderPlaceholder(){if(this.isLoaded||this.placeholder==="none")return lit.nothing;let e={shimmer:"pp-shimmer",pulse:"pp-pulse",skeleton:"pp-skeleton",blur:"",none:""}[this.placeholder];return lit.html`
257
+ ${this.placeholder==="shimmer"?lit.html`<style>${j}</style>`:lit.nothing}
258
+ <div
259
+ class=${f("np:absolute np:inset-0",e)}
260
+ style=${styleMap_js.styleMap({backgroundColor:this.placeholderColor,borderRadius:"inherit"})}>
261
+ </div>
262
+ `}renderFallback(){if(this.fallback)return lit.html`
263
+ <span
264
+ class="pp-fallback"
265
+ style=${styleMap_js.styleMap({fontSize:`${S(this.pixelSize)}px`})}>
266
+ ${this.fallback}
267
+ </span>
268
+ `;if(this.alt){let n=F(this.alt);return lit.html`
269
+ <div
270
+ class="pp-fallback np:absolute np:inset-0"
271
+ style=${styleMap_js.styleMap({background:this.bgColor??n,fontSize:`${S(this.pixelSize)}px`})}>
272
+ ${A(this.alt)}
273
+ </div>
274
+ `}let e=this.pixelSize*.5;return lit.html`
275
+ <svg
276
+ class="pp-fallback-icon"
277
+ style="width: ${e}px; height: ${e}px;"
278
+ fill="currentColor"
279
+ viewBox="0 0 24 24">
280
+ <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
281
+ </svg>
282
+ `}renderImage(){return this.hasError||!this.src?this.renderFallback():lit.html`
283
+ <img
284
+ src=${this.src}
285
+ alt=${this.alt}
286
+ loading=${this.loading}
287
+ decoding="async"
288
+ @load=${this.handleLoad}
289
+ @error=${this.handleError}
290
+ class=${f("pp-image",this.isLoaded?"pp-image-loaded":"pp-image-loading")}
291
+ draggable="false" />
292
+ `}renderRing(){if(!this.ring?.show)return lit.nothing;let e=this.ring.width??3,n=this.ring.gap??3,i=e+n,p;return this.ring.gradient&&this.ring.gradient.length>0?p=D(this.ring.gradient):p=this.ring.color??"linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888)",lit.html`
293
+ <div
294
+ class=${f("pp-ring",this.ring.animate&&"pp-ring-animated")}
295
+ style=${styleMap_js.styleMap({inset:`-${i}px`,padding:`${e}px`,background:p,borderRadius:m[this.variant]})}>
296
+ </div>
297
+ `}renderPresence(){if(!this.presence)return lit.nothing;let e=this.presence.thickness??2,n=M(this.pixelSize,e),i=z[this.presence.status],p=Math.max(0,this.pixelSize*.02);return lit.html`
298
+ <div
299
+ class=${f("pp-presence",this.presence.animate&&"pp-presence-animated")}
300
+ style=${styleMap_js.styleMap({width:`${n}px`,height:`${n}px`,backgroundColor:i,bottom:`${p}px`,right:`${p}px`,color:i})}
301
+ title=${this.presence.status}>
302
+ </div>
303
+ `}renderBadge(){if(!this.badge)return lit.nothing;let e=this.badge.position??"bottom-right",n=this.badge.content!==void 0,{size:i,fontSize:p}=E(this.pixelSize,n),l=this.badge.bgColor??"#22c55e",u=this.badge.color??"#ffffff",v=n&&this.badge.content!==void 0?L(this.badge.content,this.badge.max):null,h={"top-left":{top:"-4px",left:"-4px"},"top-right":{top:"-4px",right:"-4px"},"bottom-left":{bottom:"-4px",left:"-4px"},"bottom-right":{bottom:"-4px",right:"-4px"}};return lit.html`
304
+ <div
305
+ class=${f("pp-badge",this.badge.pulse&&"pp-badge-pulse",this.badge.glow&&"pp-badge-glow")}
306
+ style=${styleMap_js.styleMap({width:n?"auto":`${i}px`,minWidth:`${i}px`,height:`${i}px`,padding:n?"0 6px":"0",fontSize:`${p}px`,backgroundColor:l,color:u,"--pp-badge-glow-color":l,...h[e]})}>
307
+ ${v??lit.nothing}
308
+ </div>
309
+ `}renderRibbon(){if(!this.ribbon)return lit.nothing;let e=this.ribbon.position??"top-right",n=this.ribbon.bgColor??"#ef4444",i=this.ribbon.color??"#ffffff",p=y(n)?{backgroundColor:n}:{background:n},l={color:i},u=this.pixelSize*.9,v=this.pixelSize*.4,h=Math.max(8,this.pixelSize*.11);return lit.html`
310
+ <div
311
+ class=${f("pp-ribbon-container",R(e))}
312
+ style=${styleMap_js.styleMap({width:`${u}px`,height:`${v}px`})}>
313
+ <div
314
+ class=${f("pp-ribbon np:origin-center np:transform",I(e))}
315
+ style=${styleMap_js.styleMap({fontSize:`${h}px`,padding:`${h*.3}px 0`,...p,...l})}>
316
+ ${this.ribbon.icon?lit.html`<span style="margin-right: 2px">${this.ribbon.icon}</span>`:lit.nothing}
317
+ ${this.ribbon.text}
318
+ </div>
319
+ </div>
320
+ `}render(){let e=this.getContainerStyles(),n=this.interactive?.focusable||this.interactive?.pressable?0:void 0;return lit.html`
321
+ <div
322
+ class=${e.classes}
323
+ style=${styleMap_js.styleMap(e.styles)}
324
+ tabindex=${n??lit.nothing}
325
+ role=${this.interactive?.pressable?"button":lit.nothing}
326
+ aria-label=${this.alt||lit.nothing}
327
+ data-profile-picture>
328
+
329
+ <!-- Ring Effect (behind everything) -->
330
+ ${this.renderRing()}
331
+
332
+ <!-- Inner container for image clipping -->
333
+ <div
334
+ class="pp-inner"
335
+ style=${styleMap_js.styleMap({borderRadius:m[this.variant]})}>
336
+ <!-- Placeholder -->
337
+ ${this.renderPlaceholder()}
338
+
339
+ <!-- Main Image or Fallback -->
340
+ ${this.renderImage()}
341
+ </div>
342
+
343
+ <!-- Ribbon -->
344
+ ${this.renderRibbon()}
345
+
346
+ <!-- Badge -->
347
+ ${this.renderBadge()}
348
+
349
+ <!-- Presence Indicator -->
350
+ ${this.renderPresence()}
351
+ </div>
352
+ `}};o.stylesInjected=false,a([decorators_js.property({type:String})],o.prototype,"src",2),a([decorators_js.property({type:String})],o.prototype,"alt",2),a([decorators_js.property({type:String})],o.prototype,"size",2),a([decorators_js.property({type:String})],o.prototype,"variant",2),a([decorators_js.property({type:String})],o.prototype,"shadow",2),a([decorators_js.property({type:Boolean})],o.prototype,"border",2),a([decorators_js.property({type:Number,attribute:"border-width"})],o.prototype,"borderWidth",2),a([decorators_js.property({type:String,attribute:"border-color"})],o.prototype,"borderColor",2),a([decorators_js.property({type:String,attribute:"bg-color"})],o.prototype,"bgColor",2),a([decorators_js.property({type:String,attribute:"bg-gradient"})],o.prototype,"bgGradient",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"ring",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"presence",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"glow",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"ribbon",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"badge",2),a([decorators_js.property({type:String})],o.prototype,"loading",2),a([decorators_js.property({type:String})],o.prototype,"placeholder",2),a([decorators_js.property({type:String,attribute:"placeholder-color"})],o.prototype,"placeholderColor",2),a([decorators_js.property({type:String})],o.prototype,"fallback",2),a([decorators_js.property({type:Object,attribute:false})],o.prototype,"interactive",2),a([decorators_js.state()],o.prototype,"isLoaded",2),a([decorators_js.state()],o.prototype,"hasError",2),o=a([decorators_js.customElement("profile-picture")],o);k();//# sourceMappingURL=angular.cjs.map
353
+ //# sourceMappingURL=angular.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/loadStyles.ts","../src/core/types.ts","../src/core/utils.ts","../src/core/styles.ts","../src/core/ProfilePicture.ts","../src/angular.ts"],"names":["LINK_ID","loaded","loadStyles","cssUrl","getCssUrl","link","metaUrl","currentScript","scriptUrl","SIZE_MAP","PRESENCE_COLORS","SHADOW_MAP","DEFAULTS","RADIUS_MAP","cn","classes","isHexColor","color","getPositionClasses","position","getRibbonRotation","getInitials","text","words","getInitialsFontSize","containerSize","getBadgeSize","avatarSize","hasContent","size","fontSize","getPresenceSize","thickness","formatBadgeContent","content","max","createConicGradient","colors","i","start","end","hashString","str","hash","char","generateAvatarGradient","name","gradients","index","getVariantClasses","variant","getBorderClasses","width","getBackgroundStyles","bgColor","bgGradient","getShadowStyles","shadow","keyframes","allKeyframes","baseStyles","componentStyles","shimmerStyles","getGlowShadow","intensity","r","g","b","ProfilePicture","LitElement","style","sizeValue","changedProperties","bg","borderStyles","shadowStyles","glowStyles","glowColor","isInteractive","nothing","placeholderClass","html","styleMap","gradient","iconSize","ringWidth","ringGap","totalOffset","ringColor","offset","badgeSize","textColor","positionStyles","ribbonBg","ribbonColor","bgStyle","colorStyle","ribbonWidth","ribbonHeight","container","tabIndex","__decorateClass","property","state","customElement"],"mappings":"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","file":"angular.cjs","sourcesContent":["/**\n * Idempotent CSS loader for @grasco/profile-picture\n *\n * Auto-injects the component's CSS via <link> tag when the module is imported.\n * Uses relative URL detection to find styles.css in the same directory as the JS file.\n *\n * Idempotency is guaranteed through 4 layers:\n * 1. Module-level flag - prevents multiple calls in same bundle\n * 2. ID check - prevents duplicates across bundles\n * 3. href pattern check - catches manually added links\n * 4. SSR guard - prevents errors in Node.js\n */\n\nconst LINK_ID = \"grasco-profile-picture-styles\";\n\nlet loaded = false;\n\n/**\n * Load the component's CSS stylesheet\n * Safe to call multiple times - will only inject once\n */\nexport function loadStyles(): void {\n // Skip if already loaded (module-level)\n if (loaded) {\n return;\n }\n\n // Skip if SSR (no document)\n if (typeof document === \"undefined\") {\n return;\n }\n\n // Skip if link already exists by ID (idempotency across bundles)\n if (document.getElementById(LINK_ID)) {\n loaded = true;\n return;\n }\n\n // Check if any link already points to our CSS (by href pattern)\n const existingLink = document.querySelector(\n 'link[href*=\"profile-picture\"][href$=\"styles.css\"]'\n );\n if (existingLink) {\n loaded = true;\n return;\n }\n\n // Get CSS URL relative to current script\n const cssUrl = getCssUrl();\n if (!cssUrl) {\n return;\n }\n\n // Inject link tag\n const link = document.createElement(\"link\");\n link.id = LINK_ID;\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n document.head.appendChild(link);\n\n loaded = true;\n}\n\n/**\n * Get the CSS file URL based on the current script's location\n */\nfunction getCssUrl(): string | null {\n // Allow custom override via global variable\n if (\n typeof window !== \"undefined\" &&\n (window as unknown as Record<string, string>).__GRASCO_PROFILE_PICTURE_CSS__\n ) {\n return (window as unknown as Record<string, string>)\n .__GRASCO_PROFILE_PICTURE_CSS__;\n }\n\n // Try import.meta.url first (ESM - most reliable for bundlers)\n try {\n const metaUrl = import.meta.url;\n if (metaUrl) {\n const basePath = metaUrl.substring(0, metaUrl.lastIndexOf(\"/\") + 1);\n return `${basePath}styles.css`;\n }\n } catch {\n // import.meta.url not available\n }\n\n // Fallback: Get current script URL\n const currentScript = document.currentScript as HTMLScriptElement | null;\n if (currentScript?.src) {\n const scriptUrl = new URL(currentScript.src);\n const basePath = scriptUrl.href.substring(\n 0,\n scriptUrl.href.lastIndexOf(\"/\") + 1\n );\n return `${basePath}styles.css`;\n }\n\n return null;\n}\n","/**\n * Profile Picture Component - Type Definitions\n * Apple-inspired design system with modern 2025 aesthetics\n */\n\n// ─── Size System (Apple 8pt Grid) ─────────────────────────────────────────────\nexport type Size = \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\n// Size presets in pixels (following 8pt grid)\nexport const SIZE_MAP: Record<Size, number> = {\n \"2xs\": 20, // Inline, compact UI\n xs: 24, // Small avatars, lists\n sm: 32, // Default list items\n md: 40, // Navigation, headers\n lg: 48, // Profile sections\n xl: 64, // Profile pages\n \"2xl\": 80, // Hero sections\n \"3xl\": 120, // Profile modals\n};\n\n// ─── Visual Variants ──────────────────────────────────────────────────────────\nexport type Variant = \"circle\" | \"rounded\" | \"squircle\" | \"square\";\n\n// ─── Positioning ──────────────────────────────────────────────────────────────\nexport type Position =\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\";\n\n// ─── Loading & Performance ────────────────────────────────────────────────────\nexport type LoadingStrategy = \"lazy\" | \"eager\";\nexport type PlaceholderType =\n | \"shimmer\"\n | \"pulse\"\n | \"blur\"\n | \"skeleton\"\n | \"none\";\n\n// ─── Presence / Status System ─────────────────────────────────────────────────\nexport type PresenceStatus = \"online\" | \"away\" | \"busy\" | \"offline\" | \"dnd\";\n\nexport interface PresenceConfig {\n /** Current status */\n status: PresenceStatus;\n /** Show animated ring */\n animate?: boolean;\n /** Ring thickness (1-3) */\n thickness?: 1 | 2 | 3;\n}\n\n// Status colors (Apple-inspired)\nexport const PRESENCE_COLORS: Record<PresenceStatus, string> = {\n online: \"#30D158\", // Apple Green\n away: \"#FFD60A\", // Apple Yellow\n busy: \"#FF453A\", // Apple Red\n offline: \"#8E8E93\", // Apple Gray\n dnd: \"#FF453A\", // Apple Red (Do Not Disturb)\n};\n\n// ─── Ribbon Configuration ─────────────────────────────────────────────────────\nexport interface RibbonConfig {\n /** Text displayed on the ribbon */\n text: string;\n /** Position of the ribbon */\n position?: Position;\n /** Text color (CSS color) */\n color?: string;\n /** Background color (CSS color or gradient) */\n bgColor?: string;\n /** Icon before text (emoji or symbol) */\n icon?: string;\n}\n\n// ─── Badge Configuration ──────────────────────────────────────────────────────\nexport interface BadgeConfig {\n /** Badge content (text, number, or empty for dot) */\n content?: string | number;\n /** Position of the badge */\n position?: Position;\n /** Text/icon color */\n color?: string;\n /** Background color */\n bgColor?: string;\n /** Enable pulse animation */\n pulse?: boolean;\n /** Enable glow effect */\n glow?: boolean;\n /** Max value to display (shows 99+ if exceeded) */\n max?: number;\n}\n\n// ─── Glow Effect ──────────────────────────────────────────────────────────────\nexport interface GlowConfig {\n /** Glow color (defaults to border or bg color) */\n color?: string;\n /** Intensity (0-1) */\n intensity?: number;\n /** Animate the glow */\n animate?: boolean;\n}\n\n// ─── Ring Effect (like Instagram stories) ────────────────────────────────────\nexport interface RingConfig {\n /** Show ring */\n show: boolean;\n /** Ring color or gradient */\n color?: string;\n /** Gradient colors for multi-color ring */\n gradient?: string[];\n /** Ring width */\n width?: number;\n /** Gap between ring and avatar */\n gap?: number;\n /** Animate (rotate for gradient) */\n animate?: boolean;\n}\n\n// ─── Interactive States ───────────────────────────────────────────────────────\nexport interface InteractionConfig {\n /** Enable hover effects */\n hoverable?: boolean;\n /** Enable press/click effects */\n pressable?: boolean;\n /** Show focus ring on focus */\n focusable?: boolean;\n /** Cursor style */\n cursor?: \"pointer\" | \"default\" | \"zoom-in\";\n}\n\n// ─── Shadow Presets ───────────────────────────────────────────────────────────\nexport type ShadowPreset = \"none\" | \"sm\" | \"md\" | \"lg\" | \"glow\";\n\nexport const SHADOW_MAP: Record<ShadowPreset, string> = {\n none: \"none\",\n sm: \"0 1px 2px 0 rgba(0, 0, 0, 0.05)\",\n md: \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)\",\n lg: \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)\",\n glow: \"0 0 20px 0 rgba(99, 102, 241, 0.3)\",\n};\n\n// ─── Animation Presets ────────────────────────────────────────────────────────\nexport type AnimationPreset = \"none\" | \"fade\" | \"scale\" | \"slide\" | \"bounce\";\n\n// ─── Default Values ───────────────────────────────────────────────────────────\nexport const DEFAULTS = {\n size: \"md\" as Size,\n variant: \"circle\" as Variant,\n loading: \"lazy\" as LoadingStrategy,\n placeholder: \"shimmer\" as PlaceholderType,\n borderWidth: 2 as const,\n borderColor: \"#ffffff\",\n placeholderColor: \"#f3f4f6\",\n shadow: \"sm\" as ShadowPreset,\n animation: \"fade\" as AnimationPreset,\n} as const;\n\n// ─── CSS Custom Properties (for theming) ──────────────────────────────────────\nexport const CSS_VARS = {\n \"--pp-transition-duration\": \"200ms\",\n \"--pp-transition-timing\": \"cubic-bezier(0.4, 0, 0.2, 1)\",\n \"--pp-spring-timing\": \"cubic-bezier(0.34, 1.56, 0.64, 1)\",\n \"--pp-hover-scale\": \"1.05\",\n \"--pp-press-scale\": \"0.95\",\n \"--pp-focus-ring-color\": \"rgba(99, 102, 241, 0.5)\",\n \"--pp-focus-ring-width\": \"3px\",\n \"--pp-skeleton-base\": \"#e5e7eb\",\n \"--pp-skeleton-shine\": \"#f3f4f6\",\n} as const;\n\n// ─── Border Radius Presets ────────────────────────────────────────────────────\nexport const RADIUS_MAP: Record<Variant, string> = {\n circle: \"9999px\",\n rounded: \"12px\",\n squircle: \"30%\", // iOS app icon style\n square: \"0px\",\n};\n\n// ─── Full Component Props Interface ───────────────────────────────────────────\nexport interface ProfilePictureProps {\n // Core\n src?: string;\n alt?: string;\n\n // Sizing\n size?: Size | number;\n\n // Visual\n variant?: Variant;\n shadow?: ShadowPreset;\n\n // Border\n border?: boolean;\n borderWidth?: 1 | 2 | 3 | 4;\n borderColor?: string;\n\n // Background\n bgColor?: string;\n bgGradient?: string;\n\n // Effects\n glow?: GlowConfig;\n ring?: RingConfig;\n presence?: PresenceConfig;\n\n // Overlays\n ribbon?: RibbonConfig;\n badge?: BadgeConfig;\n\n // Loading\n loading?: LoadingStrategy;\n placeholder?: PlaceholderType;\n placeholderColor?: string;\n\n // Fallback\n fallback?: string;\n\n // Interaction\n interactive?: InteractionConfig;\n}\n\n// ─── Profile Picture Group Types ─────────────────────────────────────────────\n\n/** Direction for stacking avatars */\nexport type StackDirection = \"ltr\" | \"rtl\";\n\n/** Tooltip position relative to avatar */\nexport type TooltipPosition = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/** Tooltip configuration */\nexport interface TooltipConfig {\n /** Enable/disable tooltip (default: true) */\n enabled?: boolean;\n /** Position of tooltip relative to avatar */\n position?: TooltipPosition;\n /** Delay before showing tooltip in ms (default: 300) */\n delay?: number;\n}\n\n/** User data extracted from profile-picture elements */\nexport interface GroupUserData {\n /** User ID from data-user-id attribute */\n id?: string;\n /** User name from alt attribute */\n name: string;\n /** Image source URL */\n src?: string;\n /** Presence status from data-status attribute */\n status?: PresenceStatus;\n /** Reference to the profile-picture element */\n element: HTMLElement;\n /** Index in the group */\n index: number;\n\n // ─── Profile Picture Props (passed through from slotted elements) ──────────\n /** Visual variant (circle, rounded, squircle, square) */\n variant?: Variant;\n /** Shadow preset */\n shadow?: ShadowPreset;\n /** Show border */\n border?: boolean;\n /** Border width (1-4) */\n borderWidth?: 1 | 2 | 3 | 4;\n /** Border color */\n borderColor?: string;\n /** Background color */\n bgColor?: string;\n /** Background gradient */\n bgGradient?: string;\n}\n\n/** Dropdown configuration for overflow users */\nexport interface DropdownConfig {\n /** Max height of dropdown in px (default: 280) */\n maxHeight?: number;\n /** Show presence indicator dots (default: true) */\n showPresence?: boolean;\n /** Dropdown position (default: 'bottom') */\n position?: \"bottom\" | \"top\";\n}\n\n/** Profile Picture Group Props */\nexport interface ProfilePictureGroupProps {\n /** Maximum visible avatars before showing counter (default: 4) */\n max?: number;\n /** Stack direction - ltr shows first on left (default: 'ltr') */\n direction?: StackDirection;\n /** Overlap amount as percentage 0-1 (default: 0.3) */\n overlap?: number;\n /** Avatar size - inherited by children (default: 'md') */\n size?: Size | number;\n /** Spacing between avatars in px (overrides overlap calculation) */\n spacing?: number;\n /** Tooltip configuration */\n tooltip?: TooltipConfig;\n /** Dropdown configuration for overflow users */\n dropdown?: DropdownConfig;\n /** Show add button (default: false) */\n showAddButton?: boolean;\n /** Add button label for accessibility */\n addButtonLabel?: string;\n /** Enable hover lift animation (default: true) */\n animated?: boolean;\n}\n\n/** Group component defaults */\nexport const GROUP_DEFAULTS = {\n max: 4,\n direction: \"ltr\" as StackDirection,\n overlap: 0.3,\n size: \"md\" as Size,\n tooltipDelay: 300,\n dropdownMaxHeight: 280,\n animated: true,\n} as const;\n","/**\n * Profile Picture Component - Utility Functions\n * Apple-inspired design system utilities\n */\n\nimport type { Position, Size, Variant } from \"./types\";\nimport { RADIUS_MAP, SIZE_MAP } from \"./types\";\n\n/**\n * Resolve size to pixel value\n */\nexport function resolveSize(size: Size | number): number {\n if (typeof size === \"number\") {\n return size;\n }\n return SIZE_MAP[size] ?? SIZE_MAP.md;\n}\n\n/**\n * Merge class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Check if a color value is a hex code\n */\nexport function isHexColor(color: string): boolean {\n return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(color);\n}\n\n/**\n * Check if a value is a CSS color (not a Tailwind class)\n */\nexport function isCssColor(value: string): boolean {\n if (isHexColor(value)) {\n return true;\n }\n if (/^(rgb|hsl|oklch|oklab|lab|lch)a?\\s*\\(/.test(value)) {\n return true;\n }\n if (value.includes(\"gradient\")) {\n return true;\n }\n const namedColors = [\n \"transparent\",\n \"currentColor\",\n \"inherit\",\n \"white\",\n \"black\",\n ];\n return namedColors.includes(value.toLowerCase());\n}\n\n/**\n * Get position classes for overlays (ribbon, badge)\n */\nexport function getPositionClasses(position: Position): string {\n const positions: Record<Position, string> = {\n \"top-left\": \"np:top-0 np:left-0\",\n \"top-right\": \"np:top-0 np:right-0\",\n \"bottom-left\": \"np:bottom-0 np:left-0\",\n \"bottom-right\": \"np:bottom-0 np:right-0\",\n };\n return positions[position];\n}\n\n/**\n * Get ribbon rotation based on position\n */\nexport function getRibbonRotation(position: Position): string {\n const rotations: Record<Position, string> = {\n \"top-left\": \"np:-rotate-45 np:-translate-x-1/4 np:-translate-y-1/2\",\n \"top-right\": \"np:rotate-45 np:translate-x-1/4 np:-translate-y-1/2\",\n \"bottom-left\": \"np:rotate-45 np:-translate-x-1/4 np:translate-y-1/2\",\n \"bottom-right\": \"np:-rotate-45 np:translate-x-1/4 np:translate-y-1/2\",\n };\n return rotations[position];\n}\n\n/**\n * Generate initials from alt text for fallback\n * Apple-style: Single letter for single word, two letters for multiple\n */\nexport function getInitials(text: string): string {\n const cleaned = text.trim().replace(/[^\\w\\s]/g, \"\");\n const words = cleaned.split(/\\s+/).filter(Boolean);\n\n if (words.length === 0) {\n return \"?\";\n }\n if (words.length === 1) {\n return words[0].slice(0, 1).toUpperCase();\n }\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n}\n\n/**\n * Get border radius value for variant\n */\nexport function getRadius(variant: Variant): string {\n return RADIUS_MAP[variant];\n}\n\n/**\n * Calculate optimal font size for initials based on container size\n */\nexport function getInitialsFontSize(containerSize: number): number {\n return Math.round(containerSize * 0.38);\n}\n\n/**\n * Calculate badge size relative to avatar size\n */\nexport function getBadgeSize(\n avatarSize: number,\n hasContent: boolean\n): { size: number; fontSize: number } {\n const baseRatio = hasContent ? 0.32 : 0.22;\n const size = Math.max(\n hasContent ? 18 : 10,\n Math.round(avatarSize * baseRatio)\n );\n const fontSize = Math.round(size * 0.6);\n return { size, fontSize };\n}\n\n/**\n * Calculate presence indicator size\n */\nexport function getPresenceSize(\n avatarSize: number,\n thickness: 1 | 2 | 3\n): number {\n const baseSize = Math.max(8, Math.round(avatarSize * 0.25));\n return baseSize + (thickness - 1) * 2;\n}\n\n/**\n * Format badge content (e.g., 99+ for large numbers)\n */\nexport function formatBadgeContent(\n content: string | number,\n max?: number\n): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (max && content > max) {\n return `${max}+`;\n }\n return content.toString();\n}\n\n/**\n * Generate a gradient from colors array for ring effect\n */\nexport function createConicGradient(colors: string[]): string {\n if (colors.length === 0) {\n return \"transparent\";\n }\n if (colors.length === 1) {\n return colors[0];\n }\n\n const stops = colors.map((color, i) => {\n const start = (i / colors.length) * 360;\n const end = ((i + 1) / colors.length) * 360;\n return `${color} ${start}deg ${end}deg`;\n });\n\n return `conic-gradient(${stops.join(\", \")})`;\n}\n\n/**\n * Get contrast color for text on background\n * Returns white or black based on background luminance\n */\nexport function getContrastColor(bgColor: string): string {\n // Extract RGB values from hex\n if (!isHexColor(bgColor)) {\n return \"#ffffff\";\n }\n\n const hex = bgColor.replace(\"#\", \"\");\n const r = Number.parseInt(hex.slice(0, 2), 16);\n const g = Number.parseInt(hex.slice(2, 4), 16);\n const b = Number.parseInt(hex.slice(4, 6), 16);\n\n // Calculate relative luminance\n const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n\n return luminance > 0.5 ? \"#000000\" : \"#ffffff\";\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Generate a stable hash from string for consistent random colors\n */\nexport function hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash &= hash;\n }\n return Math.abs(hash);\n}\n\n/**\n * Generate a gradient from name for fallback backgrounds\n */\nexport function generateAvatarGradient(name: string): string {\n const gradients = [\n \"linear-gradient(135deg, #667eea 0%, #764ba2 100%)\",\n \"linear-gradient(135deg, #f093fb 0%, #f5576c 100%)\",\n \"linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)\",\n \"linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)\",\n \"linear-gradient(135deg, #fa709a 0%, #fee140 100%)\",\n \"linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)\",\n \"linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)\",\n \"linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)\",\n \"linear-gradient(135deg, #cd9cf2 0%, #f6f3ff 100%)\",\n \"linear-gradient(135deg, #fddb92 0%, #d1fdff 100%)\",\n ];\n\n const index = hashString(name) % gradients.length;\n return gradients[index];\n}\n\n/**\n * Apply will-change optimization for animations\n */\nexport function getWillChangeProperty(\n hasAnimation: boolean,\n hasHover: boolean\n): string | undefined {\n if (!(hasAnimation || hasHover)) {\n return undefined;\n }\n const properties: string[] = [];\n if (hasAnimation) {\n properties.push(\"opacity\");\n }\n if (hasHover) {\n properties.push(\"transform\");\n }\n return properties.join(\", \");\n}\n\n/**\n * Check if user prefers reduced motion\n */\nexport function prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n// ─── Profile Picture Group Utilities ─────────────────────────────────────────\n\nimport type { GroupUserData, PresenceStatus, StackDirection } from \"./types\";\nimport { GROUP_DEFAULTS } from \"./types\";\n\n/**\n * Calculate the pixel size for group avatars\n */\nexport function getGroupAvatarSize(size: Size | number): number {\n if (typeof size === \"number\") {\n return size;\n }\n return SIZE_MAP[size] ?? SIZE_MAP[GROUP_DEFAULTS.size];\n}\n\n/**\n * Calculate visible and hidden avatar counts\n */\nexport function calculateAvatarCounts(\n total: number,\n max: number,\n showAddButton: boolean\n): { visible: number; hidden: number; showCounter: boolean } {\n const effectiveMax = showAddButton ? max - 1 : max;\n\n if (total <= effectiveMax) {\n return { visible: total, hidden: 0, showCounter: false };\n }\n\n // Show (max - 1) avatars + counter\n const visible = effectiveMax - 1;\n const hidden = total - visible;\n return { visible, hidden, showCounter: true };\n}\n\n/**\n * Calculate position offset for stacked avatars\n */\nexport function calculateStackPosition(\n index: number,\n avatarSize: number,\n overlap: number,\n _direction: StackDirection,\n spacing?: number\n): number {\n const step = spacing ?? avatarSize * (1 - overlap);\n const offset = index * step;\n\n // For RTL, we need to reverse the positioning\n // This is handled at the component level by reversing the order\n return offset;\n}\n\n/**\n * Calculate z-index for stacked avatars\n * First avatar (index 0) has highest z-index to appear on top\n */\nexport function calculateStackZIndex(\n index: number,\n total: number,\n direction: StackDirection\n): number {\n if (direction === \"ltr\") {\n // LTR: First item on top (highest z-index)\n return total - index;\n }\n // RTL: Last item on top\n return index + 1;\n}\n\n/**\n * Calculate the total width of the stacked group\n */\nexport function calculateGroupWidth(\n count: number,\n avatarSize: number,\n overlap: number,\n spacing?: number\n): number {\n if (count === 0) {\n return 0;\n }\n if (count === 1) {\n return avatarSize;\n }\n\n const step = spacing ?? avatarSize * (1 - overlap);\n return avatarSize + step * (count - 1);\n}\n\n/**\n * Extract user data from a profile-picture element\n */\nexport function extractUserData(\n element: HTMLElement,\n index: number\n): GroupUserData {\n return {\n id: element.getAttribute(\"data-user-id\") ?? undefined,\n name: element.getAttribute(\"alt\") ?? `User ${index + 1}`,\n src: element.getAttribute(\"src\") ?? undefined,\n status:\n (element.getAttribute(\"data-status\") as PresenceStatus) ?? undefined,\n element,\n index,\n };\n}\n\n/**\n * Extract all user data from child profile-picture elements\n */\nexport function extractAllUserData(container: HTMLElement): GroupUserData[] {\n const children = container.querySelectorAll(\"profile-picture\");\n return Array.from(children).map((el, index) =>\n extractUserData(el as HTMLElement, index)\n );\n}\n\n/**\n * Get initials for counter display (e.g., \"+5\")\n */\nexport function formatCounterText(count: number): string {\n if (count > 99) {\n return \"+99\";\n }\n return `+${count}`;\n}\n\n/**\n * Calculate tooltip position relative to avatar\n */\nexport function calculateTooltipPosition(\n avatarRect: DOMRect,\n tooltipWidth: number,\n tooltipHeight: number,\n position: \"top\" | \"bottom\" | \"left\" | \"right\" = \"top\",\n gap = 8\n): { top: number; left: number } {\n const { top, left, width, height } = avatarRect;\n const centerX = left + width / 2;\n const centerY = top + height / 2;\n\n switch (position) {\n case \"top\":\n return {\n top: top - tooltipHeight - gap,\n left: centerX - tooltipWidth / 2,\n };\n case \"bottom\":\n return {\n top: top + height + gap,\n left: centerX - tooltipWidth / 2,\n };\n case \"left\":\n return {\n top: centerY - tooltipHeight / 2,\n left: left - tooltipWidth - gap,\n };\n case \"right\":\n return {\n top: centerY - tooltipHeight / 2,\n left: left + width + gap,\n };\n }\n}\n\n/**\n * Clamp tooltip position within viewport\n */\nexport function clampTooltipPosition(\n position: { top: number; left: number },\n tooltipWidth: number,\n tooltipHeight: number,\n padding = 8\n): { top: number; left: number } {\n const viewport = {\n width: typeof window !== \"undefined\" ? window.innerWidth : 1920,\n height: typeof window !== \"undefined\" ? window.innerHeight : 1080,\n };\n\n return {\n top: clamp(\n position.top,\n padding,\n viewport.height - tooltipHeight - padding\n ),\n left: clamp(\n position.left,\n padding,\n viewport.width - tooltipWidth - padding\n ),\n };\n}\n","/**\n * Profile Picture Component - Styles & Animations\n * Apple-inspired design system with modern 2025 aesthetics\n */\n\nimport type { ShadowPreset, Variant } from \"./types\";\nimport { RADIUS_MAP, SHADOW_MAP } from \"./types\";\nimport { isHexColor } from \"./utils\";\n\n/**\n * Get variant-specific border radius styles\n */\nexport function getVariantStyles(variant: Variant): Record<string, string> {\n return { borderRadius: RADIUS_MAP[variant] };\n}\n\n/**\n * Get variant classes (Tailwind)\n */\nexport function getVariantClasses(variant: Variant): string {\n const variants: Record<Variant, string> = {\n circle: \"np:rounded-full\",\n rounded: \"np:rounded-xl\",\n squircle: \"np:rounded-[30%]\",\n square: \"np:rounded-none\",\n };\n return variants[variant];\n}\n\n/**\n * Get border styles\n */\nexport function getBorderClasses(\n width: 1 | 2 | 3 | 4,\n color: string\n): { className: string; style: Record<string, string> } {\n const widthClasses: Record<1 | 2 | 3 | 4, string> = {\n 1: \"np:border\",\n 2: \"np:border-2\",\n 3: \"np:border-[3px]\",\n 4: \"np:border-4\",\n };\n\n return {\n className: widthClasses[width],\n style: {\n borderColor: color,\n borderStyle: \"solid\",\n },\n };\n}\n\n/**\n * Get background styles (solid color or gradient)\n */\nexport function getBackgroundStyles(\n bgColor?: string,\n bgGradient?: string\n): { className: string; style?: Record<string, string> } {\n if (bgGradient) {\n return {\n className: \"\",\n style: { background: bgGradient },\n };\n }\n\n if (bgColor) {\n if (bgColor.includes(\"gradient\")) {\n return {\n className: \"\",\n style: { background: bgColor },\n };\n }\n return {\n className: \"\",\n style: { backgroundColor: bgColor },\n };\n }\n\n return { className: \"np:bg-gray-100\" };\n}\n\n/**\n * Get shadow styles\n */\nexport function getShadowStyles(shadow: ShadowPreset): Record<string, string> {\n return { boxShadow: SHADOW_MAP[shadow] };\n}\n\n/**\n * CSS Keyframe animations - Apple-inspired, physics-based\n */\nexport const keyframes = {\n // Shimmer loading effect\n shimmer: `\n@keyframes pp-shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(100%); }\n}`,\n\n // Pulse animation (gentle breathe effect)\n pulse: `\n@keyframes pp-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(0.98); }\n}`,\n\n // Skeleton loading pulse\n skeleton: `\n@keyframes pp-skeleton {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}`,\n\n // Badge bounce entrance\n badgeBounce: `\n@keyframes pp-badge-bounce {\n 0% { transform: scale(0) translateY(10px); opacity: 0; }\n 50% { transform: scale(1.2) translateY(-2px); }\n 100% { transform: scale(1) translateY(0); opacity: 1; }\n}`,\n\n // Ring rotation (for gradient rings)\n ringRotate: `\n@keyframes pp-ring-rotate {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}`,\n\n // Presence indicator pulse\n presencePulse: `\n@keyframes pp-presence-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 currentColor; }\n 50% { box-shadow: 0 0 0 4px transparent; }\n}`,\n\n // Glow animation\n glow: `\n@keyframes pp-glow {\n 0%, 100% { box-shadow: 0 0 20px 0 var(--pp-glow-color, rgba(99, 102, 241, 0.3)); }\n 50% { box-shadow: 0 0 30px 5px var(--pp-glow-color, rgba(99, 102, 241, 0.5)); }\n}`,\n\n // Fade in\n fadeIn: `\n@keyframes pp-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}`,\n\n // Scale in (spring-like)\n scaleIn: `\n@keyframes pp-scale-in {\n 0% { transform: scale(0.8); opacity: 0; }\n 50% { transform: scale(1.05); }\n 100% { transform: scale(1); opacity: 1; }\n}`,\n};\n\n/**\n * All keyframes combined for injection\n */\nexport const allKeyframes = Object.values(keyframes).join(\"\\n\");\n\n/**\n * Component base styles\n */\nexport const baseStyles = `\n/* Profile Picture Component Styles */\n.pp-container {\n --pp-transition-duration: 200ms;\n --pp-transition-timing: cubic-bezier(0.4, 0, 0.2, 1);\n --pp-spring-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n flex-shrink: 0;\n}\n\n/* Inner container for image clipping - allows badges/rings to overflow */\n.pp-inner {\n position: absolute;\n inset: 0;\n overflow: hidden;\n border-radius: inherit;\n}\n\n/* Interactive states */\n.pp-interactive {\n cursor: pointer;\n transition: transform var(--pp-transition-duration) var(--pp-spring-timing),\n box-shadow var(--pp-transition-duration) var(--pp-transition-timing);\n}\n\n.pp-interactive:hover {\n transform: scale(1.05);\n}\n\n.pp-interactive:active {\n transform: scale(0.95);\n}\n\n.pp-interactive:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5);\n}\n\n/* Image styles */\n.pp-image {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n transition: opacity var(--pp-transition-duration) var(--pp-transition-timing);\n}\n\n.pp-image-loading {\n opacity: 0;\n}\n\n.pp-image-loaded {\n opacity: 1;\n}\n\n/* Fallback styles */\n.pp-fallback {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.9);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;\n letter-spacing: 0.02em;\n}\n\n.pp-fallback-icon {\n color: rgba(156, 163, 175, 0.8);\n}\n\n/* Shimmer placeholder */\n.pp-shimmer {\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.pp-shimmer::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.4) 50%,\n transparent 100%\n );\n animation: pp-shimmer 1.5s infinite;\n}\n\n/* Pulse placeholder */\n.pp-pulse {\n animation: pp-pulse 2s ease-in-out infinite;\n}\n\n/* Skeleton placeholder */\n.pp-skeleton {\n background: linear-gradient(90deg, #e5e7eb 0%, #f3f4f6 50%, #e5e7eb 100%);\n background-size: 200% 100%;\n animation: pp-skeleton 1.5s ease-in-out infinite;\n}\n\n/* Badge styles */\n.pp-badge {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n line-height: 1;\n animation: pp-badge-bounce 0.4s var(--pp-spring-timing);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);\n border: 2px solid white;\n}\n\n.pp-badge-pulse {\n animation: pp-badge-bounce 0.4s var(--pp-spring-timing),\n pp-presence-pulse 2s ease-in-out infinite 0.4s;\n}\n\n.pp-badge-glow {\n box-shadow: 0 0 10px 2px var(--pp-badge-glow-color, currentColor);\n}\n\n/* Ribbon styles */\n.pp-ribbon-container {\n position: absolute;\n z-index: 10;\n overflow: hidden;\n}\n\n.pp-ribbon {\n position: absolute;\n width: 100%;\n text-align: center;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n}\n\n/* Ring effect (Instagram-style) */\n.pp-ring {\n position: absolute;\n inset: -4px;\n border-radius: inherit;\n padding: 3px;\n background: var(--pp-ring-color, linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888));\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n\n.pp-ring-animated {\n animation: pp-ring-rotate 3s linear infinite;\n}\n\n/* Presence indicator */\n.pp-presence {\n position: absolute;\n bottom: 0;\n right: 0;\n border-radius: 9999px;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.pp-presence-animated {\n animation: pp-presence-pulse 2s ease-in-out infinite;\n}\n\n/* Glow effect */\n.pp-glow {\n animation: pp-glow 2s ease-in-out infinite;\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .pp-container,\n .pp-interactive,\n .pp-image,\n .pp-shimmer::after,\n .pp-pulse,\n .pp-skeleton,\n .pp-badge,\n .pp-ring-animated,\n .pp-presence-animated,\n .pp-glow {\n animation: none !important;\n transition: none !important;\n }\n}\n`;\n\n/**\n * All styles combined (keyframes + base styles)\n */\nexport const componentStyles = `${allKeyframes}\\n${baseStyles}`;\n\n/**\n * Shimmer styles for inline injection (legacy support)\n */\nexport const shimmerStyles = `\n@keyframes np-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n}\n.np-shimmer {\n background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%);\n background-size: 200% 100%;\n animation: np-shimmer 1.5s infinite;\n}\n`;\n\n/**\n * Generate glow shadow with custom color\n */\nexport function getGlowShadow(color: string, intensity = 0.3): string {\n if (isHexColor(color)) {\n // Convert hex to rgba\n const r = Number.parseInt(color.slice(1, 3), 16);\n const g = Number.parseInt(color.slice(3, 5), 16);\n const b = Number.parseInt(color.slice(5, 7), 16);\n return `0 0 20px 0 rgba(${r}, ${g}, ${b}, ${intensity})`;\n }\n return `0 0 20px 0 ${color}`;\n}\n\n/**\n * Get shimmer classes (legacy)\n */\nexport function getShimmerClasses(): string {\n return \"np-shimmer\";\n}\n\n// ─── Profile Picture Group Styles ────────────────────────────────────────────\n\n/**\n * Group component keyframe animations\n */\nexport const groupKeyframes = `\n@keyframes ppg-tooltip-in {\n from {\n opacity: 0;\n transform: translateY(4px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@keyframes ppg-dropdown-in {\n from {\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@keyframes ppg-avatar-lift {\n from {\n transform: translateY(0) scale(1);\n }\n to {\n transform: translateY(-4px) scale(1.08);\n }\n}\n`;\n\n/**\n * Group component base styles - Apple-inspired\n */\nexport const groupBaseStyles = `\n/* Profile Picture Group Container */\n.ppg-container {\n --ppg-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);\n --ppg-spring: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);\n --ppg-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --ppg-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);\n --ppg-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);\n --ppg-radius: 12px;\n --ppg-counter-bg: #f5f5f7;\n --ppg-counter-text: #1d1d1f;\n --ppg-add-bg: #f5f5f7;\n --ppg-add-hover: #e8e8ed;\n --ppg-add-icon: #86868b;\n --ppg-border: rgba(0, 0, 0, 0.08);\n --ppg-tooltip-bg: rgba(29, 29, 31, 0.95);\n --ppg-tooltip-text: #ffffff;\n --ppg-dropdown-bg: #ffffff;\n --ppg-dropdown-hover: #f5f5f7;\n\n position: relative;\n display: inline-flex;\n align-items: center;\n isolation: isolate;\n}\n\n/* Avatar wrapper for positioning */\n.ppg-avatar-wrapper {\n position: absolute;\n top: 0;\n transition: transform var(--ppg-spring), z-index 0s;\n cursor: pointer;\n border-radius: 9999px;\n}\n\n.ppg-avatar-wrapper:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.4);\n}\n\n/* Hover lift animation */\n.ppg-animated .ppg-avatar-wrapper:hover {\n z-index: 100 !important;\n animation: ppg-avatar-lift var(--ppg-spring) forwards;\n}\n\n.ppg-avatar-wrapper:hover {\n z-index: 100 !important;\n}\n\n/* Nested profile-picture styling */\n.ppg-avatar-wrapper profile-picture {\n display: block;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n}\n\n/* Counter button */\n.ppg-counter {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n background: var(--ppg-counter-bg);\n color: var(--ppg-counter-text);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;\n font-weight: 600;\n font-size: 13px;\n letter-spacing: -0.01em;\n cursor: pointer;\n border: none;\n box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.95), var(--ppg-shadow-sm);\n transition: transform var(--ppg-spring), background-color var(--ppg-transition);\n user-select: none;\n -webkit-user-select: none;\n}\n\n.ppg-counter:hover {\n background: #e8e8ed;\n transform: scale(1.05);\n}\n\n.ppg-counter:active {\n transform: scale(0.98);\n}\n\n.ppg-counter:focus-visible {\n outline: none;\n box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.95), 0 0 0 4px rgba(0, 122, 255, 0.4);\n}\n\n/* Add button */\n.ppg-add-button {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n background: var(--ppg-add-bg);\n border: 2px dashed var(--ppg-border);\n cursor: pointer;\n transition: all var(--ppg-spring);\n box-shadow: var(--ppg-shadow-sm);\n}\n\n.ppg-add-button:hover {\n background: var(--ppg-add-hover);\n border-color: rgba(0, 0, 0, 0.15);\n transform: scale(1.05);\n}\n\n.ppg-add-button:active {\n transform: scale(0.98);\n}\n\n.ppg-add-button:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.4);\n}\n\n.ppg-add-icon {\n color: var(--ppg-add-icon);\n transition: color var(--ppg-transition);\n}\n\n.ppg-add-button:hover .ppg-add-icon {\n color: #1d1d1f;\n}\n\n/* Tooltip */\n.ppg-tooltip {\n position: fixed;\n z-index: 9999;\n padding: 6px 12px;\n background: var(--ppg-tooltip-bg);\n color: var(--ppg-tooltip-text);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n font-size: 13px;\n font-weight: 500;\n border-radius: 8px;\n box-shadow: var(--ppg-shadow-lg);\n pointer-events: none;\n white-space: nowrap;\n animation: ppg-tooltip-in 150ms ease-out;\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n}\n\n.ppg-tooltip::after {\n content: '';\n position: absolute;\n width: 8px;\n height: 8px;\n background: inherit;\n transform: rotate(45deg);\n}\n\n.ppg-tooltip[data-position=\"top\"]::after {\n bottom: -4px;\n left: 50%;\n margin-left: -4px;\n}\n\n.ppg-tooltip[data-position=\"bottom\"]::after {\n top: -4px;\n left: 50%;\n margin-left: -4px;\n}\n\n/* Dropdown */\n.ppg-dropdown {\n position: absolute;\n z-index: 1000;\n min-width: 200px;\n max-width: 280px;\n background: var(--ppg-dropdown-bg);\n border-radius: var(--ppg-radius);\n box-shadow: var(--ppg-shadow-lg);\n border: 1px solid var(--ppg-border);\n overflow: hidden;\n animation: ppg-dropdown-in 200ms ease-out;\n}\n\n.ppg-dropdown[data-position=\"bottom\"] {\n top: calc(100% + 8px);\n}\n\n.ppg-dropdown[data-position=\"top\"] {\n bottom: calc(100% + 8px);\n}\n\n.ppg-dropdown-header {\n padding: 12px 16px 8px;\n font-size: 12px;\n font-weight: 600;\n color: #86868b;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n border-bottom: 1px solid var(--ppg-border);\n}\n\n.ppg-dropdown-list {\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.ppg-dropdown-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px;\n cursor: pointer;\n transition: background-color var(--ppg-transition);\n}\n\n.ppg-dropdown-item:hover {\n background: var(--ppg-dropdown-hover);\n}\n\n.ppg-dropdown-item:focus-visible {\n outline: none;\n background: var(--ppg-dropdown-hover);\n}\n\n.ppg-dropdown-avatar {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 9999px;\n object-fit: cover;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n}\n\n.ppg-dropdown-avatar-fallback {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 9999px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n font-weight: 600;\n color: white;\n}\n\n.ppg-dropdown-info {\n flex: 1;\n min-width: 0;\n}\n\n.ppg-dropdown-name {\n font-size: 14px;\n font-weight: 500;\n color: #1d1d1f;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ppg-dropdown-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #86868b;\n margin-top: 2px;\n}\n\n.ppg-dropdown-presence {\n width: 8px;\n height: 8px;\n border-radius: 9999px;\n}\n\n.ppg-dropdown-presence[data-status=\"online\"] {\n background: #30D158;\n}\n\n.ppg-dropdown-presence[data-status=\"away\"] {\n background: #FFD60A;\n}\n\n.ppg-dropdown-presence[data-status=\"busy\"],\n.ppg-dropdown-presence[data-status=\"dnd\"] {\n background: #FF453A;\n}\n\n.ppg-dropdown-presence[data-status=\"offline\"] {\n background: #8E8E93;\n}\n\n/* Backdrop for dropdown */\n.ppg-backdrop {\n position: fixed;\n inset: 0;\n z-index: 999;\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n .ppg-container,\n .ppg-avatar-wrapper,\n .ppg-counter,\n .ppg-add-button,\n .ppg-tooltip,\n .ppg-dropdown {\n animation: none !important;\n transition: none !important;\n }\n\n .ppg-animated .ppg-avatar-wrapper:hover {\n animation: none !important;\n transform: none !important;\n }\n}\n\n/* Dark mode support */\n@media (prefers-color-scheme: dark) {\n .ppg-container {\n --ppg-counter-bg: #2c2c2e;\n --ppg-counter-text: #ffffff;\n --ppg-add-bg: #2c2c2e;\n --ppg-add-hover: #3a3a3c;\n --ppg-add-icon: #98989d;\n --ppg-border: rgba(255, 255, 255, 0.1);\n --ppg-dropdown-bg: #2c2c2e;\n --ppg-dropdown-hover: #3a3a3c;\n }\n\n .ppg-avatar-wrapper profile-picture {\n box-shadow: 0 0 6px 1.5px rgb(28 28 30 / 16%), var(--ppg-shadow-sm);\n }\n\n .ppg-counter {\n box-shadow: 0 0 0 1.5px rgba(28, 28, 30, 0.95), var(--ppg-shadow-sm);\n }\n\n .ppg-dropdown-name {\n color: #ffffff;\n }\n\n .ppg-dropdown-header {\n color: #98989d;\n border-color: rgba(255, 255, 255, 0.1);\n }\n}\n`;\n\n/**\n * All group styles combined\n */\nexport const groupStyles = `${groupKeyframes}\\n${groupBaseStyles}`;\n","/**\n * ProfilePicture Web Component\n * Apple-inspired design system with modern 2025 aesthetics\n *\n * A lightweight, framework-agnostic profile picture component\n * with advanced features: presence indicators, rings, badges, and ribbons.\n */\n\nimport { html, LitElement, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport {\n componentStyles,\n getBackgroundStyles,\n getBorderClasses,\n getGlowShadow,\n getShadowStyles,\n getVariantClasses,\n shimmerStyles,\n} from \"./styles\";\nimport type {\n BadgeConfig,\n GlowConfig,\n InteractionConfig,\n LoadingStrategy,\n PlaceholderType,\n Position,\n PresenceConfig,\n RibbonConfig,\n RingConfig,\n ShadowPreset,\n Size,\n Variant,\n} from \"./types\";\nimport { DEFAULTS, PRESENCE_COLORS, RADIUS_MAP, SIZE_MAP } from \"./types\";\nimport {\n cn,\n createConicGradient,\n formatBadgeContent,\n generateAvatarGradient,\n getBadgeSize,\n getInitials,\n getInitialsFontSize,\n getPositionClasses,\n getPresenceSize,\n getRibbonRotation,\n isHexColor,\n} from \"./utils\";\n\n@customElement(\"profile-picture\")\nexport class ProfilePicture extends LitElement {\n private static stylesInjected = false;\n\n // Use Light DOM for Tailwind compatibility\n protected createRenderRoot() {\n ProfilePicture.injectStylesOnce();\n return this;\n }\n\n private static injectStylesOnce() {\n if (ProfilePicture.stylesInjected || typeof document === \"undefined\") {\n return;\n }\n const style = document.createElement(\"style\");\n style.textContent = componentStyles;\n document.head.appendChild(style);\n ProfilePicture.stylesInjected = true;\n }\n\n // ─── Core Properties ────────────────────────────────────────────────────────\n @property({ type: String }) src = \"\";\n @property({ type: String }) alt = \"\";\n\n // ─── Sizing ─────────────────────────────────────────────────────────────────\n @property({ type: String }) size: Size | string = DEFAULTS.size;\n\n // ─── Visual Variant ─────────────────────────────────────────────────────────\n @property({ type: String }) variant: Variant = DEFAULTS.variant;\n\n // ─── Shadow ─────────────────────────────────────────────────────────────────\n @property({ type: String }) shadow: ShadowPreset = DEFAULTS.shadow;\n\n // ─── Border ─────────────────────────────────────────────────────────────────\n @property({ type: Boolean }) border = false;\n @property({ type: Number, attribute: \"border-width\" }) borderWidth:\n | 1\n | 2\n | 3\n | 4 = DEFAULTS.borderWidth;\n @property({ type: String, attribute: \"border-color\" }) borderColor: string =\n DEFAULTS.borderColor;\n\n // ─── Background ─────────────────────────────────────────────────────────────\n @property({ type: String, attribute: \"bg-color\" }) bgColor?: string;\n @property({ type: String, attribute: \"bg-gradient\" }) bgGradient?: string;\n\n // ─── Ring Effect (Instagram-style) ──────────────────────────────────────────\n @property({ type: Object, attribute: false }) ring?: RingConfig;\n\n // ─── Presence Indicator ─────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) presence?: PresenceConfig;\n\n // ─── Glow Effect ────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) glow?: GlowConfig;\n\n // ─── Ribbon ─────────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) ribbon?: RibbonConfig;\n\n // ─── Badge ──────────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) badge?: BadgeConfig;\n\n // ─── Loading & Performance ──────────────────────────────────────────────────\n @property({ type: String }) loading: LoadingStrategy = DEFAULTS.loading;\n @property({ type: String }) placeholder: PlaceholderType =\n DEFAULTS.placeholder;\n @property({ type: String, attribute: \"placeholder-color\" })\n placeholderColor: string = DEFAULTS.placeholderColor;\n\n // ─── Fallback ───────────────────────────────────────────────────────────────\n @property({ type: String }) fallback?: string;\n\n // ─── Interaction ────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) interactive?: InteractionConfig;\n\n // ─── Internal State ─────────────────────────────────────────────────────────\n @state() private isLoaded = false;\n @state() private hasError = false;\n private previousSrc = \"\";\n\n private get pixelSize(): number {\n const sizeValue = this.size as Size | number;\n return typeof sizeValue === \"number\"\n ? sizeValue\n : (SIZE_MAP[sizeValue as Size] ?? SIZE_MAP[DEFAULTS.size]);\n }\n\n protected willUpdate(changedProperties: Map<string, unknown>): void {\n if (changedProperties.has(\"src\") && this.src !== this.previousSrc) {\n this.isLoaded = false;\n this.hasError = false;\n this.previousSrc = this.src;\n }\n }\n\n private handleLoad() {\n this.isLoaded = true;\n this.dispatchEvent(\n new CustomEvent(\"load\", { bubbles: true, composed: true })\n );\n }\n\n private handleError() {\n this.hasError = true;\n this.isLoaded = true;\n this.dispatchEvent(\n new CustomEvent(\"error\", { bubbles: true, composed: true })\n );\n }\n\n private getContainerStyles() {\n const bg = getBackgroundStyles(this.bgColor, this.bgGradient);\n const borderStyles = this.border\n ? getBorderClasses(this.borderWidth, this.borderColor)\n : null;\n const shadowStyles = getShadowStyles(this.shadow);\n\n // Handle glow effect\n let glowStyles: Record<string, string> = {};\n if (this.glow) {\n const glowColor = this.glow.color ?? this.borderColor ?? \"#6366f1\";\n glowStyles = {\n \"--pp-glow-color\": glowColor,\n boxShadow: getGlowShadow(glowColor, this.glow.intensity ?? 0.3),\n };\n }\n\n const isInteractive =\n this.interactive?.hoverable || this.interactive?.pressable;\n\n return {\n classes: cn(\n \"pp-container\",\n getVariantClasses(this.variant),\n bg.className,\n borderStyles?.className,\n isInteractive && \"pp-interactive\",\n this.glow?.animate && \"pp-glow\"\n ),\n styles: {\n width: `${this.pixelSize}px`,\n height: `${this.pixelSize}px`,\n borderRadius: RADIUS_MAP[this.variant],\n ...bg.style,\n ...borderStyles?.style,\n ...shadowStyles,\n ...glowStyles,\n cursor:\n this.interactive?.cursor ?? (isInteractive ? \"pointer\" : \"default\"),\n },\n };\n }\n\n private renderPlaceholder() {\n if (this.isLoaded || this.placeholder === \"none\") {\n return nothing;\n }\n\n const placeholderClass = {\n shimmer: \"pp-shimmer\",\n pulse: \"pp-pulse\",\n skeleton: \"pp-skeleton\",\n blur: \"\",\n none: \"\",\n }[this.placeholder];\n\n return html`\n ${this.placeholder === \"shimmer\" ? html`<style>${shimmerStyles}</style>` : nothing}\n <div\n class=${cn(\"np:absolute np:inset-0\", placeholderClass)}\n style=${styleMap({\n backgroundColor: this.placeholderColor,\n borderRadius: \"inherit\",\n })}>\n </div>\n `;\n }\n\n private renderFallback() {\n // Use custom fallback text if provided\n if (this.fallback) {\n return html`\n <span\n class=\"pp-fallback\"\n style=${styleMap({ fontSize: `${getInitialsFontSize(this.pixelSize)}px` })}>\n ${this.fallback}\n </span>\n `;\n }\n\n // Generate initials from alt text\n if (this.alt) {\n const gradient = generateAvatarGradient(this.alt);\n return html`\n <div\n class=\"pp-fallback np:absolute np:inset-0\"\n style=${styleMap({\n background: this.bgColor ?? gradient,\n fontSize: `${getInitialsFontSize(this.pixelSize)}px`,\n })}>\n ${getInitials(this.alt)}\n </div>\n `;\n }\n\n // Default user icon\n const iconSize = this.pixelSize * 0.5;\n return html`\n <svg\n class=\"pp-fallback-icon\"\n style=\"width: ${iconSize}px; height: ${iconSize}px;\"\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n `;\n }\n\n private renderImage() {\n if (this.hasError || !this.src) {\n return this.renderFallback();\n }\n\n return html`\n <img\n src=${this.src}\n alt=${this.alt}\n loading=${this.loading}\n decoding=\"async\"\n @load=${this.handleLoad}\n @error=${this.handleError}\n class=${cn(\"pp-image\", this.isLoaded ? \"pp-image-loaded\" : \"pp-image-loading\")}\n draggable=\"false\" />\n `;\n }\n\n private renderRing() {\n if (!this.ring?.show) {\n return nothing;\n }\n\n const ringWidth = this.ring.width ?? 3;\n const ringGap = this.ring.gap ?? 3;\n const totalOffset = ringWidth + ringGap;\n\n let ringColor: string;\n if (this.ring.gradient && this.ring.gradient.length > 0) {\n ringColor = createConicGradient(this.ring.gradient);\n } else {\n ringColor =\n this.ring.color ??\n \"linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888)\";\n }\n\n return html`\n <div\n class=${cn(\"pp-ring\", this.ring.animate && \"pp-ring-animated\")}\n style=${styleMap({\n inset: `-${totalOffset}px`,\n padding: `${ringWidth}px`,\n background: ringColor,\n borderRadius: RADIUS_MAP[this.variant],\n })}>\n </div>\n `;\n }\n\n private renderPresence() {\n if (!this.presence) {\n return nothing;\n }\n\n const thickness = this.presence.thickness ?? 2;\n const size = getPresenceSize(this.pixelSize, thickness);\n const color = PRESENCE_COLORS[this.presence.status];\n\n // Position offset based on avatar size\n const offset = Math.max(0, this.pixelSize * 0.02);\n\n return html`\n <div\n class=${cn(\"pp-presence\", this.presence.animate && \"pp-presence-animated\")}\n style=${styleMap({\n width: `${size}px`,\n height: `${size}px`,\n backgroundColor: color,\n bottom: `${offset}px`,\n right: `${offset}px`,\n color,\n })}\n title=${this.presence.status}>\n </div>\n `;\n }\n\n private renderBadge() {\n if (!this.badge) {\n return nothing;\n }\n\n const position = this.badge.position ?? \"bottom-right\";\n const hasContent = this.badge.content !== undefined;\n const { size: badgeSize, fontSize } = getBadgeSize(\n this.pixelSize,\n hasContent\n );\n\n const bgColor = this.badge.bgColor ?? \"#22c55e\";\n const textColor = this.badge.color ?? \"#ffffff\";\n\n // Format content (99+ for large numbers)\n const content =\n hasContent && this.badge.content !== undefined\n ? formatBadgeContent(this.badge.content, this.badge.max)\n : null;\n\n const positionStyles: Record<Position, Record<string, string>> = {\n \"top-left\": { top: \"-4px\", left: \"-4px\" },\n \"top-right\": { top: \"-4px\", right: \"-4px\" },\n \"bottom-left\": { bottom: \"-4px\", left: \"-4px\" },\n \"bottom-right\": { bottom: \"-4px\", right: \"-4px\" },\n };\n\n return html`\n <div\n class=${cn(\n \"pp-badge\",\n this.badge.pulse && \"pp-badge-pulse\",\n this.badge.glow && \"pp-badge-glow\"\n )}\n style=${styleMap({\n width: hasContent ? \"auto\" : `${badgeSize}px`,\n minWidth: `${badgeSize}px`,\n height: `${badgeSize}px`,\n padding: hasContent ? \"0 6px\" : \"0\",\n fontSize: `${fontSize}px`,\n backgroundColor: bgColor,\n color: textColor,\n \"--pp-badge-glow-color\": bgColor,\n ...positionStyles[position],\n })}>\n ${content ?? nothing}\n </div>\n `;\n }\n\n private renderRibbon() {\n if (!this.ribbon) {\n return nothing;\n }\n\n const position = this.ribbon.position ?? \"top-right\";\n const ribbonBg = this.ribbon.bgColor ?? \"#ef4444\";\n const ribbonColor = this.ribbon.color ?? \"#ffffff\";\n\n const bgStyle = isHexColor(ribbonBg)\n ? { backgroundColor: ribbonBg }\n : { background: ribbonBg };\n const colorStyle = { color: ribbonColor };\n\n // Calculate ribbon dimensions based on avatar size\n const ribbonWidth = this.pixelSize * 0.9;\n const ribbonHeight = this.pixelSize * 0.4;\n const fontSize = Math.max(8, this.pixelSize * 0.11);\n\n return html`\n <div\n class=${cn(\"pp-ribbon-container\", getPositionClasses(position))}\n style=${styleMap({\n width: `${ribbonWidth}px`,\n height: `${ribbonHeight}px`,\n })}>\n <div\n class=${cn(\n \"pp-ribbon np:origin-center np:transform\",\n getRibbonRotation(position)\n )}\n style=${styleMap({\n fontSize: `${fontSize}px`,\n padding: `${fontSize * 0.3}px 0`,\n ...bgStyle,\n ...colorStyle,\n })}>\n ${this.ribbon.icon ? html`<span style=\"margin-right: 2px\">${this.ribbon.icon}</span>` : nothing}\n ${this.ribbon.text}\n </div>\n </div>\n `;\n }\n\n render() {\n const container = this.getContainerStyles();\n\n const tabIndex =\n this.interactive?.focusable || this.interactive?.pressable\n ? 0\n : undefined;\n\n return html`\n <div\n class=${container.classes}\n style=${styleMap(container.styles)}\n tabindex=${tabIndex ?? nothing}\n role=${this.interactive?.pressable ? \"button\" : nothing}\n aria-label=${this.alt || nothing}\n data-profile-picture>\n\n <!-- Ring Effect (behind everything) -->\n ${this.renderRing()}\n\n <!-- Inner container for image clipping -->\n <div\n class=\"pp-inner\"\n style=${styleMap({\n borderRadius: RADIUS_MAP[this.variant],\n })}>\n <!-- Placeholder -->\n ${this.renderPlaceholder()}\n\n <!-- Main Image or Fallback -->\n ${this.renderImage()}\n </div>\n\n <!-- Ribbon -->\n ${this.renderRibbon()}\n\n <!-- Badge -->\n ${this.renderBadge()}\n\n <!-- Presence Indicator -->\n ${this.renderPresence()}\n </div>\n `;\n }\n}\n\n// Export types for TypeScript users\nexport type {\n BadgeConfig,\n GlowConfig,\n InteractionConfig,\n LoadingStrategy,\n PlaceholderType,\n Position,\n PresenceConfig,\n PresenceStatus,\n RibbonConfig,\n RingConfig,\n ShadowPreset,\n Size,\n Variant,\n} from \"./types\";\n\n// Ensure component is registered\ndeclare global {\n interface HTMLElementTagNameMap {\n \"profile-picture\": ProfilePicture;\n }\n}\n\nexport default ProfilePicture;\n","/**\n * Angular entry point\n */\n\n// Auto-load styles when module is imported\nimport { loadStyles } from \"./core/loadStyles\";\n\nloadStyles();\n\nexport * from \"./wrappers/angular\";\n"]}