@grasco/profile-picture 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/angular.d.ts CHANGED
@@ -7,7 +7,7 @@ import { LitElement } from 'lit';
7
7
  */
8
8
  type Size = "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
9
9
  type Variant = "circle" | "rounded" | "squircle" | "square";
10
- type Position = "top-left" | "top-right" | "bottom-left" | "bottom-right";
10
+ type Position = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
11
11
  type LoadingStrategy = "lazy" | "eager";
12
12
  type PlaceholderType = "shimmer" | "pulse" | "blur" | "skeleton" | "none";
13
13
  type PresenceStatus = "online" | "away" | "busy" | "offline" | "dnd";
@@ -40,6 +40,8 @@ interface BadgeConfig {
40
40
  color?: string;
41
41
  /** Background color */
42
42
  bgColor?: string;
43
+ /** Border radius (CSS value, e.g., "8px", "50%", "9999px") */
44
+ borderRadius?: string;
43
45
  /** Enable pulse animation */
44
46
  pulse?: boolean;
45
47
  /** Enable glow effect */
@@ -86,6 +88,130 @@ interface InteractionConfig {
86
88
  cursor?: "pointer" | "default" | "zoom-in";
87
89
  }
88
90
  type ShadowPreset = "none" | "sm" | "md" | "lg" | "glow";
91
+ /**
92
+ * Base props interface shared across all framework wrappers.
93
+ * This ensures type consistency between React, Vue, Svelte, and Angular.
94
+ */
95
+ interface ProfilePictureProps {
96
+ /** Image source URL */
97
+ src?: string;
98
+ /** Alt text for accessibility and fallback initials */
99
+ alt?: string;
100
+ /** External customer ID for CDN image loading */
101
+ extCustomerId?: string;
102
+ /** Predefined size or custom pixel value */
103
+ size?: Size | number;
104
+ /** Shape variant */
105
+ variant?: Variant;
106
+ /** Shadow preset */
107
+ shadow?: ShadowPreset;
108
+ /** Enable border */
109
+ border?: boolean;
110
+ /** Border width in pixels */
111
+ borderWidth?: 1 | 2 | 3 | 4 | 5 | 6 | 8;
112
+ /** Border color (CSS color value) */
113
+ borderColor?: string;
114
+ /** Rotation angle in degrees */
115
+ rotation?: number;
116
+ /** Background color (CSS color value) */
117
+ bgColor?: string;
118
+ /** Background gradient (CSS gradient value) */
119
+ bgGradient?: string;
120
+ /** Glow effect configuration */
121
+ glow?: GlowConfig;
122
+ /** Ring effect configuration (Instagram-style) */
123
+ ring?: RingConfig;
124
+ /** Presence indicator configuration */
125
+ presence?: PresenceConfig;
126
+ /** Ribbon configuration */
127
+ ribbon?: RibbonConfig;
128
+ /** Badge configuration */
129
+ badge?: BadgeConfig;
130
+ /** Loading strategy */
131
+ loading?: LoadingStrategy;
132
+ /** Placeholder type while loading */
133
+ placeholder?: PlaceholderType;
134
+ /** Placeholder background color */
135
+ placeholderColor?: string;
136
+ /** Custom fallback text (overrides initials from alt) */
137
+ fallback?: string;
138
+ /** Interactive behavior configuration */
139
+ interactive?: InteractionConfig;
140
+ }
141
+ /** Direction for stacking avatars */
142
+ type StackDirection = "ltr" | "rtl";
143
+ /** Tooltip position relative to avatar */
144
+ type TooltipPosition = "top" | "bottom" | "left" | "right";
145
+ /** Tooltip configuration */
146
+ interface TooltipConfig {
147
+ /** Enable/disable tooltip (default: true) */
148
+ enabled?: boolean;
149
+ /** Position of tooltip relative to avatar */
150
+ position?: TooltipPosition;
151
+ /** Delay before showing tooltip in ms (default: 300) */
152
+ delay?: number;
153
+ }
154
+ /** User data extracted from profile-picture elements */
155
+ interface GroupUserData {
156
+ /** User ID from data-user-id attribute */
157
+ id?: string;
158
+ /** User name from alt attribute */
159
+ name: string;
160
+ /** Image source URL */
161
+ src?: string;
162
+ /** Presence status from data-status attribute */
163
+ status?: PresenceStatus;
164
+ /** Reference to the profile-picture element */
165
+ element: HTMLElement;
166
+ /** Index in the group */
167
+ index: number;
168
+ /** Visual variant (circle, rounded, squircle, square) */
169
+ variant?: Variant;
170
+ /** Shadow preset */
171
+ shadow?: ShadowPreset;
172
+ /** Show border */
173
+ border?: boolean;
174
+ /** Border width (1-8) */
175
+ borderWidth?: 1 | 2 | 3 | 4 | 5 | 6 | 8;
176
+ /** Border color */
177
+ borderColor?: string;
178
+ /** Background color */
179
+ bgColor?: string;
180
+ /** Background gradient */
181
+ bgGradient?: string;
182
+ }
183
+ /** Dropdown configuration for overflow users */
184
+ interface DropdownConfig {
185
+ /** Max height of dropdown in px (default: 280) */
186
+ maxHeight?: number;
187
+ /** Show presence indicator dots (default: true) */
188
+ showPresence?: boolean;
189
+ /** Dropdown position (default: 'bottom') */
190
+ position?: "bottom" | "top";
191
+ }
192
+ /** Profile Picture Group Props */
193
+ interface ProfilePictureGroupProps {
194
+ /** Maximum visible avatars before showing counter (default: 4) */
195
+ max?: number;
196
+ /** Stack direction - ltr shows first on left (default: 'ltr') */
197
+ direction?: StackDirection;
198
+ /** Overlap amount as percentage 0-1 (default: 0.3) */
199
+ overlap?: number;
200
+ /** Avatar size - inherited by children (default: 'md') */
201
+ size?: Size | number;
202
+ /** Spacing between avatars in px (overrides overlap calculation) */
203
+ spacing?: number;
204
+ /** Tooltip configuration */
205
+ tooltip?: TooltipConfig;
206
+ /** Dropdown configuration for overflow users */
207
+ dropdown?: DropdownConfig;
208
+ /** Show add button (default: false) */
209
+ showAddButton?: boolean;
210
+ /** Add button label for accessibility */
211
+ addButtonLabel?: string;
212
+ /** Enable hover lift animation (default: true) */
213
+ animated?: boolean;
214
+ }
89
215
 
90
216
  declare class ProfilePicture extends LitElement {
91
217
  private static stylesInjected;
@@ -162,4 +288,64 @@ declare global {
162
288
  }
163
289
  }
164
290
 
165
- export type { BadgeConfig, LoadingStrategy, PlaceholderType, Position, RibbonConfig, Size, Variant };
291
+ declare class ProfilePictureGroup extends LitElement {
292
+ protected createRenderRoot(): this;
293
+ max: 4;
294
+ direction: StackDirection;
295
+ overlap: 0.3;
296
+ size: Size | string;
297
+ spacing?: number;
298
+ tooltip?: TooltipConfig;
299
+ dropdown?: DropdownConfig;
300
+ showAddButton: boolean;
301
+ addButtonLabel: string;
302
+ animated: true;
303
+ rotationAmount: number;
304
+ private users;
305
+ private dropdownOpen;
306
+ private tooltipData;
307
+ private tooltipTimeout;
308
+ private slotObserver;
309
+ private portalContainer;
310
+ private counterRef;
311
+ private get pixelSize();
312
+ private get tooltipEnabled();
313
+ private get tooltipPosition();
314
+ private get tooltipDelay();
315
+ private get dropdownMaxHeight();
316
+ private get showPresence();
317
+ private get dropdownPosition();
318
+ connectedCallback(): void;
319
+ disconnectedCallback(): void;
320
+ private setupSlotObserver;
321
+ private updateUsers;
322
+ private createPortal;
323
+ private destroyPortal;
324
+ private updatePortalContent;
325
+ private handleAvatarClick;
326
+ private handleAvatarHover;
327
+ private handleAvatarLeave;
328
+ private clearTooltipTimeout;
329
+ private handleCounterClick;
330
+ private readonly handleBackdropClick;
331
+ private handleDropdownItemClick;
332
+ private handleAddClick;
333
+ private handleKeyDown;
334
+ private renderAvatar;
335
+ private renderProfilePicture;
336
+ private renderCounter;
337
+ private renderAddButton;
338
+ private renderTooltip;
339
+ private renderDropdownItem;
340
+ private formatStatus;
341
+ protected updated(changedProperties: Map<PropertyKey, unknown>): void;
342
+ render(): lit_html.TemplateResult<1>;
343
+ }
344
+
345
+ declare global {
346
+ interface HTMLElementTagNameMap {
347
+ "profile-picture-group": ProfilePictureGroup;
348
+ }
349
+ }
350
+
351
+ export type { BadgeConfig, DropdownConfig, GlowConfig, GroupUserData, InteractionConfig, LoadingStrategy, PlaceholderType, Position, PresenceConfig, PresenceStatus, ProfilePictureGroupProps, ProfilePictureProps, RibbonConfig, RingConfig, ShadowPreset, Size, StackDirection, TooltipConfig, TooltipPosition, Variant };
package/dist/angular.js CHANGED
@@ -1,371 +1,2 @@
1
- import {LitElement,nothing,html}from'lit';import {property,state,customElement}from'lit/decorators.js';import {styleMap}from'lit/directives/style-map.js';var Q=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var s=(t,r,e,n)=>{for(var i=n>1?void 0:n?_(r,e):r,a=t.length-1,d;a>=0;a--)(d=t[a])&&(i=(n?d(r,e,i):d(i))||i);return n&&i&&Q(r,e,i),i};var I="grasco-profile-picture-styles",w=false;function $(){if(w||typeof document>"u")return;if(document.getElementById(I)){w=true;return}if(document.querySelector('link[href*="profile-picture"][href$="styles.css"]')){w=true;return}let r=P();if(!r)return;let e=document.createElement("link");e.id=I,e.rel="stylesheet",e.href=r,document.head.appendChild(e),w=true;}function P(){if(typeof window<"u"&&window.__GRASCO_PROFILE_PICTURE_CSS__)return window.__GRASCO_PROFILE_PICTURE_CSS__;try{let r=import.meta.url;if(r)return `${r.substring(0,r.lastIndexOf("/")+1)}dist/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)}dist/styles.css`}return null}var v={"2xs":20,xs:24,sm:32,md:40,lg:48,xl:64,"2xl":80,"3xl":120},R={online:"#30D158",away:"#FFD60A",busy:"#FF453A",offline:"#8E8E93",dnd:"#FF453A"},z={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)"},u={size:"md",variant:"circle",loading:"lazy",placeholder:"shimmer",borderWidth:2,borderColor:"#ffffff",placeholderColor:"#f3f4f6",shadow:"sm"};var x={circle:"9999px",rounded:"12px",squircle:"30%",square:"0px"};function b(...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 E(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 A(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 T(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 L(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 B(t,r){return Math.max(8,Math.round(t*.25))+(r-1)*2}function U(t,r){return typeof t=="string"?t:r&&t>r?`${r}+`:t.toString()}function F(t){return t.length===0?"transparent":t.length===1?t[0]:`conic-gradient(${t.map((e,n)=>{let i=n/t.length*360,a=(n+1)/t.length*360;return `${e} ${i}deg ${a}deg`}).join(", ")})`}function ee(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 M(t,r,e){let i=Math.max(0,Math.min(100,t))/100*360;return `conic-gradient(from 270deg, ${r} 0deg ${i}deg, ${e} ${i}deg 360deg)`}function D(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=ee(t)%r.length;return r[e]}function N(t){return t<=80?"80":t<=120?"120":t<=240?"240":t<=480?"480":"960"}function O(t){if(!(t&&y(t)))return "light";let r=t.replace("#","");r.length===3&&(r=r.split("").map(d=>d+d).join(""));let e=Number.parseInt(r.slice(0,2),16),n=Number.parseInt(r.slice(2,4),16),i=Number.parseInt(r.slice(4,6),16);return (.299*e+.587*n+.114*i)/255>.5?"light":"dark"}function G(t,r,e,n,i){let a=t.endsWith("/")?t.slice(0,-1):t,d=`${r}_${e}_${n}.webp`;return `${a}/api/profile-picture/cdn/${d}?hostname=${i}`}function j(t){return {circle:"np:rounded-full",rounded:"np:rounded-xl",squircle:"np:rounded-[30%]",square:"np:rounded-none"}[t]}function V(t,r){return {className:{1:"np:border",2:"np:border-2",3:"np:border-[3px]",4:"np:border-4",5:"np:border-[5px]",6:"np:border-[6px]",8:"np:border-8"}[t],style:{borderColor:r,borderStyle:"solid"}}}function Y(t,r){return r?{className:"",style:{background:r}}:t?t.includes("gradient")?{className:"",style:{background:t}}:{className:"",style:{backgroundColor:t}}:{className:"",style:{backgroundColor:"#e7e7e7"}}}function H(t){return {boxShadow:z[t]}}var te={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
- }`},ne=Object.values(te).join(`
40
- `),re=`
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
- }
164
-
165
- .pp-badge-with-icon {
166
- gap: 4px;
167
- }
168
-
169
- .pp-badge-icon {
170
- display: inline-flex;
171
- align-items: center;
172
- justify-content: center;
173
- line-height: 1;
174
- flex-shrink: 0;
175
- }
176
-
177
- .pp-badge-pulse {
178
- animation: pp-badge-bounce 0.4s var(--pp-spring-timing),
179
- pp-presence-pulse 2s ease-in-out infinite 0.4s;
180
- }
181
-
182
- .pp-badge-glow {
183
- box-shadow: 0 0 10px 2px var(--pp-badge-glow-color, currentColor);
184
- }
185
-
186
- /* Ribbon styles */
187
- .pp-ribbon-container {
188
- position: absolute;
189
- z-index: 10;
190
- overflow: hidden;
191
- }
192
-
193
- .pp-ribbon {
194
- position: absolute;
195
- width: 100%;
196
- text-align: center;
197
- font-weight: 600;
198
- font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;
199
- text-transform: uppercase;
200
- letter-spacing: 0.05em;
201
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
202
- }
203
-
204
- /* Ring effect (Instagram-style) */
205
- .pp-ring {
206
- position: absolute;
207
- inset: -4px;
208
- border-radius: inherit;
209
- padding: 3px;
210
- background: var(--pp-ring-color, linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888));
211
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
212
- mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
213
- -webkit-mask-composite: xor;
214
- mask-composite: exclude;
215
- transition: background 0.3s ease;
216
- }
217
-
218
- .pp-ring-animated {
219
- animation: pp-ring-rotate 3s linear infinite;
220
- }
221
-
222
- .pp-ring-progress {
223
- /* Progress rings should not animate rotation */
224
- animation: none;
225
- }
226
-
227
- /* Presence indicator */
228
- .pp-presence {
229
- position: absolute;
230
- bottom: 0;
231
- right: 0;
232
- border-radius: 9999px;
233
- border: 2px solid white;
234
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
235
- }
236
-
237
- .pp-presence-animated {
238
- animation: pp-presence-pulse 2s ease-in-out infinite;
239
- }
240
-
241
- /* Glow effect */
242
- .pp-glow {
243
- animation: pp-glow 2s ease-in-out infinite;
244
- }
245
-
246
- /* Reduced motion support */
247
- @media (prefers-reduced-motion: reduce) {
248
- .pp-container,
249
- .pp-interactive,
250
- .pp-image,
251
- .pp-shimmer::after,
252
- .pp-pulse,
253
- .pp-skeleton,
254
- .pp-badge,
255
- .pp-ring-animated,
256
- .pp-presence-animated,
257
- .pp-glow {
258
- animation: none !important;
259
- transition: none !important;
260
- }
261
- }
262
- `,W=`${ne}
263
- ${re}`,J=`
264
- @keyframes np-shimmer {
265
- 0% { background-position: -200% 0; }
266
- 100% { background-position: 200% 0; }
267
- }
268
- .np-shimmer {
269
- background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%);
270
- background-size: 200% 100%;
271
- animation: np-shimmer 1.5s infinite;
272
- }
273
- `;function q(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 LitElement{constructor(){super(...arguments);this.src="";this.alt="";this.size=u.size;this.variant=u.variant;this.shadow=u.shadow;this.border=false;this.borderWidth=u.borderWidth;this.borderColor=u.borderColor;this.rotation=0;this.loading=u.loading;this.placeholder=u.placeholder;this.placeholderColor=u.placeholderColor;this.isLoaded=false;this.hasError=false;this.cdnLoadFailed=false;this.previousSrc="";this.RETRY_DELAY_MS=3e4;}static setCdnBaseUrl(e){o.cdnBaseUrl=e,o.instances.forEach(n=>{n.extCustomerId&&!n.cdnImageUrl&&(n.cdnLoadFailed=false,n.retryTimeoutId&&(clearTimeout(n.retryTimeoutId),n.retryTimeoutId=void 0),n.previousExtCustomerId||(n.previousExtCustomerId=n.extCustomerId),n.loadCdnImage());});}static getCdnBaseUrl(){return o.cdnBaseUrl}createRenderRoot(){return o.injectStylesOnce(),this}static injectStylesOnce(){if(o.stylesInjected||typeof document>"u")return;let e=document.createElement("style");e.textContent=W,document.head.appendChild(e),o.stylesInjected=true;}get pixelSize(){let e=this.size;return typeof e=="number"?e:v[e]??v[u.size]}connectedCallback(){super.connectedCallback(),o.instances.add(this);}disconnectedCallback(){super.disconnectedCallback(),o.instances.delete(this),this.retryTimeoutId&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=void 0);}firstUpdated(){this.extCustomerId&&o.cdnBaseUrl&&(this.previousExtCustomerId=this.extCustomerId,this.loadCdnImage());}updated(e){super.updated(e),this.extCustomerId&&o.cdnBaseUrl&&!this.cdnImageUrl&&(this.cdnLoadFailed||!this.previousExtCustomerId)&&(this.previousExtCustomerId||(this.previousExtCustomerId=this.extCustomerId),this.cdnLoadFailed=false,this.loadCdnImage());}willUpdate(e){e.has("src")&&this.src!==this.previousSrc&&(this.isLoaded=false,this.hasError=false,this.previousSrc=this.src),(e.has("extCustomerId")||e.has("size")||e.has("bgColor"))&&this.extCustomerId!==this.previousExtCustomerId&&(this.previousExtCustomerId=this.extCustomerId,this.cdnImageUrl=void 0,this.cdnLoadFailed=false,this.isLoaded=false,this.hasError=false,this.retryTimeoutId&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=void 0),this.loadCdnImage());}handleLoad(){this.isLoaded=true,this.dispatchEvent(new CustomEvent("load",{bubbles:true,composed:true}));}handleError(){if(this.cdnImageUrl&&!this.cdnLoadFailed){this.cdnLoadFailed=true,this.cdnImageUrl=void 0,this.dispatchEvent(new CustomEvent("cdn-error",{bubbles:true,composed:true,detail:{error:"Image load failed"}})),this.retryTimeoutId&&clearTimeout(this.retryTimeoutId),this.retryTimeoutId=setTimeout(()=>{this.retryTimeoutId=void 0,this.extCustomerId&&o.cdnBaseUrl&&(this.cdnLoadFailed=false,this.hasError=false,this.isLoaded=false,this.loadCdnImage());},this.RETRY_DELAY_MS);return}this.hasError=true,this.isLoaded=true,this.dispatchEvent(new CustomEvent("error",{bubbles:true,composed:true}));}loadCdnImage(){if(!(this.extCustomerId&&o.cdnBaseUrl)){this.cdnLoadFailed=true;return}let e=N(this.pixelSize),n=O(this.bgColor),i=typeof window<"u"?window.location.hostname:"localhost";this.cdnImageUrl=G(o.cdnBaseUrl,this.extCustomerId,e,n,i);}getContainerStyles(){let e=Y(this.bgColor,this.bgGradient),n=this.border?V(this.borderWidth,this.borderColor):null,i=H(this.shadow),a={};if(this.glow){let f=this.glow.color??this.borderColor??"#6366f1";a={"--pp-glow-color":f,boxShadow:q(f,this.glow.intensity??.3)};}let d=this.interactive?.hoverable||this.interactive?.pressable;return {classes:b("pp-container",j(this.variant),e.className,n?.className,d&&"pp-interactive",this.glow?.animate&&"pp-glow"),styles:{width:`${this.pixelSize}px`,height:`${this.pixelSize}px`,borderRadius:x[this.variant],...e.style,...n?.style,...i,...a,cursor:this.interactive?.cursor??(d?"pointer":"default"),transform:this.rotation?`rotate(${this.rotation}deg)`:void 0}}}renderPlaceholder(){if(this.isLoaded||this.placeholder==="none")return nothing;let e={shimmer:"pp-shimmer",pulse:"pp-pulse",skeleton:"pp-skeleton",blur:"",none:""}[this.placeholder];return html`
274
- ${this.placeholder==="shimmer"?html`<style>${J}</style>`:nothing}
275
- <div
276
- class=${b("np:absolute np:inset-0",e)}
277
- style=${styleMap({backgroundColor:this.placeholderColor,borderRadius:"inherit"})}>
278
- </div>
279
- `}renderFallback(){if(this.fallback)return html`
280
- <span
281
- class="pp-fallback"
282
- style=${styleMap({fontSize:`${S(this.pixelSize)}px`})}>
283
- ${this.fallback}
284
- </span>
285
- `;if(this.alt){let n=D(this.alt);return html`
286
- <div
287
- class="pp-fallback np:absolute np:inset-0"
288
- style=${styleMap({background:this.bgColor??n,fontSize:`${S(this.pixelSize)}px`})}>
289
- ${T(this.alt)}
290
- </div>
291
- `}let e=this.pixelSize*.5;return html`
292
- <svg
293
- class="pp-fallback-icon"
294
- style="width: ${e}px; height: ${e}px;"
295
- fill="currentColor"
296
- viewBox="0 0 24 24">
297
- <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" />
298
- </svg>
299
- `}renderImage(){let e=!!(this.extCustomerId&&o.cdnBaseUrl),n;return this.cdnImageUrl?n=this.cdnImageUrl:(!e||this.cdnLoadFailed)&&(n=this.src),this.hasError||!n?this.renderFallback():html`
300
- <img
301
- src=${n}
302
- alt=${this.alt}
303
- loading=${this.loading}
304
- decoding="async"
305
- @load=${this.handleLoad}
306
- @error=${this.handleError}
307
- class=${b("pp-image",this.isLoaded?"pp-image-loaded":"pp-image-loading")}
308
- draggable="false" />
309
- `}renderRing(){if(!this.ring?.show)return nothing;let e=this.ring.width??3,n=this.ring.gap??3,i=e+n,a,d=this.ring.progress!==void 0;if(d){let f=this.ring.progress??0,m=this.ring.color??"#30D158",h=this.ring.emptyColor??"#8E8E93";a=M(f,m,h);}else this.ring.gradient&&this.ring.gradient.length>0?a=F(this.ring.gradient):a=this.ring.color??"linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888)";return html`
310
- <div
311
- class=${b("pp-ring",this.ring.animate&&!d&&"pp-ring-animated",d&&"pp-ring-progress")}
312
- style=${styleMap({inset:`-${i}px`,padding:`${e}px`,background:a,borderRadius:x[this.variant]})}>
313
- </div>
314
- `}renderPresence(){if(!this.presence)return nothing;let e=this.presence.thickness??2,n=B(this.pixelSize,e),i=R[this.presence.status],a=Math.max(0,this.pixelSize*.02);return html`
315
- <div
316
- class=${b("pp-presence",this.presence.animate&&"pp-presence-animated")}
317
- style=${styleMap({width:`${n}px`,height:`${n}px`,backgroundColor:i,bottom:`${a}px`,right:`${a}px`,color:i})}
318
- title=${this.presence.status}>
319
- </div>
320
- `}renderBadge(){if(!this.badge)return nothing;let e=this.badge.position??"bottom-right",n=this.badge.content!==void 0,i=this.badge.icon!==void 0,a=n||i,{size:d,fontSize:f}=L(this.pixelSize,a),m=this.badge.bgColor??"#22c55e",h=this.badge.color??"#ffffff",Z=n&&this.badge.content!==void 0?U(this.badge.content,this.badge.max):null,k=i?this.badge.icon:null,K=f*.9,X={"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 html`
321
- <div
322
- class=${b("pp-badge",this.badge.pulse&&"pp-badge-pulse",this.badge.glow&&"pp-badge-glow",i&&"pp-badge-with-icon")}
323
- style=${styleMap({width:a?"auto":`${d}px`,minWidth:`${d}px`,height:`${d}px`,padding:a?"0 6px":"0",fontSize:`${f}px`,backgroundColor:m,color:h,"--pp-badge-glow-color":m,gap:i&&n?"4px":"0",...X[e]})}>
324
- ${k?html`<span class="pp-badge-icon" style=${styleMap({fontSize:`${K}px`})}>${k}</span>`:nothing}
325
- ${Z??nothing}
326
- </div>
327
- `}renderRibbon(){if(!this.ribbon)return nothing;let e=this.ribbon.position??"top-right",n=this.ribbon.bgColor??"#ef4444",i=this.ribbon.color??"#ffffff",a=y(n)?{backgroundColor:n}:{background:n},d={color:i},f=this.pixelSize*.9,m=this.pixelSize*.4,h=Math.max(8,this.pixelSize*.11);return html`
328
- <div
329
- class=${b("pp-ribbon-container",E(e))}
330
- style=${styleMap({width:`${f}px`,height:`${m}px`})}>
331
- <div
332
- class=${b("pp-ribbon np:origin-center np:transform",A(e))}
333
- style=${styleMap({fontSize:`${h}px`,padding:`${h*.3}px 0`,...a,...d})}>
334
- ${this.ribbon.icon?html`<span style="margin-right: 2px">${this.ribbon.icon}</span>`:nothing}
335
- ${this.ribbon.text}
336
- </div>
337
- </div>
338
- `}render(){let e=this.getContainerStyles(),n=this.interactive?.focusable||this.interactive?.pressable?0:void 0;return html`
339
- <div
340
- class=${e.classes}
341
- style=${styleMap(e.styles)}
342
- tabindex=${n??nothing}
343
- role=${this.interactive?.pressable?"button":nothing}
344
- aria-label=${this.alt||nothing}
345
- data-profile-picture>
346
-
347
- <!-- Ring Effect (behind everything) -->
348
- ${this.renderRing()}
349
-
350
- <!-- Inner container for image clipping -->
351
- <div
352
- class="pp-inner"
353
- style=${styleMap({borderRadius:x[this.variant]})}>
354
- <!-- Placeholder -->
355
- ${this.renderPlaceholder()}
356
-
357
- <!-- Main Image or Fallback -->
358
- ${this.renderImage()}
359
- </div>
360
-
361
- <!-- Ribbon -->
362
- ${this.renderRibbon()}
363
-
364
- <!-- Badge -->
365
- ${this.renderBadge()}
366
-
367
- <!-- Presence Indicator -->
368
- ${this.renderPresence()}
369
- </div>
370
- `}};o.stylesInjected=false,o.cdnBaseUrl="",o.instances=new Set,s([property({type:String})],o.prototype,"src",2),s([property({type:String})],o.prototype,"alt",2),s([property({type:String,attribute:"ext-customer-id"})],o.prototype,"extCustomerId",2),s([property({type:String})],o.prototype,"size",2),s([property({type:String})],o.prototype,"variant",2),s([property({type:String})],o.prototype,"shadow",2),s([property({type:Boolean})],o.prototype,"border",2),s([property({type:Number,attribute:"border-width"})],o.prototype,"borderWidth",2),s([property({type:String,attribute:"border-color"})],o.prototype,"borderColor",2),s([property({type:Number})],o.prototype,"rotation",2),s([property({type:String,attribute:"bg-color"})],o.prototype,"bgColor",2),s([property({type:String,attribute:"bg-gradient"})],o.prototype,"bgGradient",2),s([property({type:Object,attribute:"ring",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"ring",2),s([property({type:Object,attribute:"presence",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"presence",2),s([property({type:Object,attribute:"glow",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"glow",2),s([property({type:Object,attribute:"ribbon",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"ribbon",2),s([property({type:Object,attribute:"badge",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"badge",2),s([property({type:String})],o.prototype,"loading",2),s([property({type:String})],o.prototype,"placeholder",2),s([property({type:String,attribute:"placeholder-color"})],o.prototype,"placeholderColor",2),s([property({type:String})],o.prototype,"fallback",2),s([property({type:Object,attribute:"interactive",converter:{fromAttribute:e=>{if(e)try{return JSON.parse(e)}catch{return}},toAttribute:e=>e?JSON.stringify(e):null}})],o.prototype,"interactive",2),s([state()],o.prototype,"isLoaded",2),s([state()],o.prototype,"hasError",2),s([state()],o.prototype,"cdnImageUrl",2),s([state()],o.prototype,"cdnLoadFailed",2),o=s([customElement("profile-picture")],o);$();//# sourceMappingURL=angular.js.map
1
+ var s="grasco-profile-picture-styles",n=false;function i(){if(n||typeof document>"u")return;if(document.getElementById(s)){n=true;return}if(document.querySelector('link[href*="profile-picture"][href$="styles.css"]')){n=true;return}let t=o();if(!t)return;let e=document.createElement("link");e.id=s,e.rel="stylesheet",e.href=t,document.head.appendChild(e),n=true;}function o(){if(typeof window<"u"&&window.__GRASCO_PROFILE_PICTURE_CSS__)return window.__GRASCO_PROFILE_PICTURE_CSS__;try{let t=import.meta.url;if(t)return `${t.substring(0,t.lastIndexOf("/")+1)}dist/styles.css`}catch{}let r=document.currentScript;if(r?.src){let t=new URL(r.src);return `${t.href.substring(0,t.href.lastIndexOf("/")+1)}dist/styles.css`}return null}i();//# sourceMappingURL=angular.js.map
371
2
  //# sourceMappingURL=angular.js.map