@aejkatappaja/phantom-ui 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  <p align="center">
2
- <img src="logo-phantom.svg" alt="phantom-ui" width="200" />
2
+ <img src=".github/assets/logo-phantom.svg" alt="phantom-ui" width="200" />
3
+ <br />
4
+ <img src=".github/assets/phantom-ui-text.svg" alt="phantom-ui" width="320" />
3
5
  </p>
4
6
 
5
7
  <p align="center">
@@ -24,7 +26,7 @@
24
26
 
25
27
  <div align="center">
26
28
  <picture>
27
- <img src="preview.gif" alt="phantom-ui demo" width="640" />
29
+ <img src=".github/assets/phantom-ui-preview.svg" alt="phantom-ui demo" width="640" />
28
30
  </picture>
29
31
  </div>
30
32
 
@@ -69,7 +71,7 @@ Or drop in a script tag with no build step:
69
71
  </phantom-ui>
70
72
  ```
71
73
 
72
- Set `loading` to show the shimmer. Remove it to reveal the real content.
74
+ Set `loading` to show the shimmer. Remove it to reveal the real content. All child elements (including deeply nested images and media) are automatically hidden during loading.
73
75
 
74
76
  ## Framework examples
75
77
 
@@ -80,7 +82,7 @@ import "@aejkatappaja/phantom-ui";
80
82
 
81
83
  function ProfileCard({ user, isLoading }: Props) {
82
84
  return (
83
- <phantom-ui loading={isLoading || undefined}>
85
+ <phantom-ui loading={isLoading || undefined} animation="pulse" reveal={0.3}>
84
86
  <div className="card">
85
87
  <img src={user?.avatar ?? "/placeholder.png"} className="avatar" />
86
88
  <h3>{user?.name ?? "Placeholder Name"}</h3>
@@ -89,6 +91,18 @@ function ProfileCard({ user, isLoading }: Props) {
89
91
  </phantom-ui>
90
92
  );
91
93
  }
94
+
95
+ // List with repeat mode
96
+ function UserList({ users, isLoading }: Props) {
97
+ return (
98
+ <phantom-ui loading={isLoading || undefined} count={5} count-gap={8}>
99
+ <div className="row">
100
+ <img src="/placeholder.png" width="32" height="32" />
101
+ <span>Placeholder Name</span>
102
+ </div>
103
+ </phantom-ui>
104
+ );
105
+ }
92
106
  ```
93
107
 
94
108
  ### Vue
@@ -101,7 +115,7 @@ const props = defineProps<{ loading: boolean }>();
101
115
  </script>
102
116
 
103
117
  <template>
104
- <phantom-ui :loading="props.loading">
118
+ <phantom-ui :loading="props.loading" animation="breathe" stagger="0.05">
105
119
  <div class="card">
106
120
  <img src="/avatar.png" class="avatar" />
107
121
  <h3>Ada Lovelace</h3>
@@ -120,7 +134,7 @@ const props = defineProps<{ loading: boolean }>();
120
134
  export let loading = true;
121
135
  </script>
122
136
 
123
- <phantom-ui {loading}>
137
+ <phantom-ui {loading} reveal={0.4} stagger={0.03}>
124
138
  <div class="card">
125
139
  <img src="/avatar.png" alt="avatar" class="avatar" />
126
140
  <h3>Ada Lovelace</h3>
@@ -139,7 +153,7 @@ import "@aejkatappaja/phantom-ui";
139
153
  selector: "app-profile",
140
154
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
141
155
  template: `
142
- <phantom-ui [attr.loading]="loading() ? '' : null">
156
+ <phantom-ui [attr.loading]="loading() ? '' : null" animation="pulse">
143
157
  <div class="card">
144
158
  <img src="/avatar.png" class="avatar" />
145
159
  <h3>Ada Lovelace</h3>
@@ -163,7 +177,7 @@ function ProfileCard() {
163
177
  const [loading, setLoading] = createSignal(true);
164
178
 
165
179
  return (
166
- <phantom-ui attr:loading={loading() || undefined}>
180
+ <phantom-ui attr:loading={loading() || undefined} animation="shimmer" stagger={0.05}>
167
181
  <div class="card">
168
182
  <img src="/avatar.png" class="avatar" />
169
183
  <h3>Ada Lovelace</h3>
@@ -174,7 +188,7 @@ function ProfileCard() {
174
188
  }
175
189
  ```
176
190
 
177
- ### SSR frameworks (Next.js, Nuxt, SvelteKit, Remix)
191
+ ### SSR frameworks (Next.js, Nuxt, SvelteKit)
178
192
 
179
193
  The component needs browser APIs to measure the DOM. Import it client-side only:
180
194
 
@@ -286,6 +300,8 @@ declare module "@builder.io/qwik" {
286
300
  | `duration` | `number` | `1.5` | Animation cycle in seconds |
287
301
  | `stagger` | `number` | `0` | Delay in seconds between each block's animation start |
288
302
  | `reveal` | `number` | `0` | Fade-out duration in seconds when loading ends |
303
+ | `count` | `number` | `1` | Number of skeleton rows to repeat from a single template |
304
+ | `count-gap` | `number` | `0` | Gap in pixels between repeated rows |
289
305
  | `fallback-radius` | `number` | `4` | Border radius (px) for flat elements like text |
290
306
 
291
307
  ## Fine-grained control
@@ -312,6 +328,35 @@ Two data attributes let you control which elements get shimmer treatment:
312
328
  </phantom-ui>
313
329
  ```
314
330
 
331
+ ## Repeat mode
332
+
333
+ When loading a dynamic list or table, you often don't have the data yet to render N rows. The `count` attribute lets you define a single template element and generate multiple skeleton rows from it:
334
+
335
+ ```html
336
+ <phantom-ui loading count="5" count-gap="8">
337
+ <div class="user-row">
338
+ <img src="avatar.png" width="32" height="32" />
339
+ <span>John Doe</span>
340
+ <span>john@acme.io</span>
341
+ </div>
342
+ </phantom-ui>
343
+ ```
344
+
345
+ The component measures the template once, then duplicates the skeleton blocks vertically for each count. `count-gap` adds spacing (in pixels) between repeated rows. When `loading` is removed, only the real template element is shown.
346
+
347
+ This is useful with framework loops where the list is empty before data loads:
348
+
349
+ ```tsx
350
+ // React
351
+ <phantom-ui loading={!users} count={5} count-gap={8}>
352
+ <div className="row-template">
353
+ <img src="/placeholder.png" width="32" height="32" />
354
+ <span>Placeholder Name</span>
355
+ <span>placeholder@email.com</span>
356
+ </div>
357
+ </phantom-ui>
358
+ ```
359
+
315
360
  ## How it works
316
361
 
317
362
  1. Your real content is rendered in the DOM with `color: transparent` and media elements hidden. Container backgrounds and borders stay visible, preserving the natural card/section outline.
@@ -322,7 +367,7 @@ Two data attributes let you control which elements get shimmer treatment:
322
367
 
323
368
  4. An absolutely-positioned overlay renders one shimmer block per measured element, with a CSS gradient animation sweeping across each block.
324
369
 
325
- 5. A `ResizeObserver` and `MutationObserver` re-measure automatically when the layout changes (window resize, content injection, DOM mutations).
370
+ 5. A `ResizeObserver`, `MutationObserver`, and media `load` listener re-measure automatically when the layout changes (window resize, content injection, DOM mutations, or images/videos finishing loading).
326
371
 
327
372
  6. When `loading` is removed, the overlay is destroyed and real content is revealed.
328
373
 
@@ -356,6 +401,9 @@ bun run storybook # dev server on :6006
356
401
  bun run build # tsc + custom elements manifest + CDN bundle
357
402
  bun run lint # biome check
358
403
  bun run lint:fix # biome auto-fix
404
+ bun run test # browser tests (Chromium)
405
+ bun run test:all # browser tests (Chromium + Firefox + WebKit)
406
+ bun run playground # local server to test the component
359
407
  ```
360
408
 
361
409
  The `examples/` directory contains test apps for React, Vue, Solid, Angular, and Qwik, each wired to the local package.
@@ -8,14 +8,8 @@
8
8
  "declarations": [
9
9
  {
10
10
  "kind": "class",
11
- "description": "`<phantom-ui>` -- A structure-aware shimmer skeleton loader.\n\nWraps real content and, when `loading` is true, measures the DOM structure\nof the slotted children to generate perfectly-aligned shimmer overlay blocks.",
11
+ "description": "",
12
12
  "name": "PhantomUi",
13
- "slots": [
14
- {
15
- "description": "The real content to show (or measure for skeleton generation)",
16
- "name": ""
17
- }
18
- ],
19
13
  "members": [
20
14
  {
21
15
  "kind": "field",
@@ -99,6 +93,26 @@
99
93
  "description": "Fade-out duration in seconds when loading ends (0 = instant)",
100
94
  "attribute": "reveal"
101
95
  },
96
+ {
97
+ "kind": "field",
98
+ "name": "count",
99
+ "type": {
100
+ "text": "number"
101
+ },
102
+ "default": "1",
103
+ "description": "Number of skeleton rows to generate from a single template element",
104
+ "attribute": "count"
105
+ },
106
+ {
107
+ "kind": "field",
108
+ "name": "countGap",
109
+ "type": {
110
+ "text": "number"
111
+ },
112
+ "default": "0",
113
+ "description": "Gap in pixels between each repeated skeleton row (only used when count > 1)",
114
+ "attribute": "count-gap"
115
+ },
102
116
  {
103
117
  "kind": "field",
104
118
  "name": "_blocks",
@@ -135,6 +149,15 @@
135
149
  "privacy": "private",
136
150
  "default": "null"
137
151
  },
152
+ {
153
+ "kind": "field",
154
+ "name": "_loadHandler",
155
+ "type": {
156
+ "text": "(() => void) | null"
157
+ },
158
+ "privacy": "private",
159
+ "default": "null"
160
+ },
138
161
  {
139
162
  "kind": "field",
140
163
  "name": "_measureScheduled",
@@ -211,76 +234,94 @@
211
234
  ],
212
235
  "attributes": [
213
236
  {
237
+ "name": "loading",
214
238
  "type": {
215
239
  "text": "boolean"
216
240
  },
217
- "description": "Whether to show the shimmer overlay or the real content",
218
- "name": "loading",
219
241
  "default": "false",
242
+ "description": "Whether to show the shimmer overlay or the real content",
220
243
  "fieldName": "loading"
221
244
  },
222
245
  {
246
+ "name": "shimmer-color",
223
247
  "type": {
224
248
  "text": "string"
225
249
  },
226
- "description": "Color of the animated shimmer gradient wave",
227
- "name": "shimmer-color",
228
250
  "default": "\"rgba(255, 255, 255, 0.3)\"",
251
+ "description": "Color of the animated shimmer gradient wave",
229
252
  "fieldName": "shimmerColor"
230
253
  },
231
254
  {
255
+ "name": "background-color",
232
256
  "type": {
233
257
  "text": "string"
234
258
  },
235
- "description": "Background color of each shimmer block",
236
- "name": "background-color",
237
259
  "default": "\"rgba(255, 255, 255, 0.08)\"",
260
+ "description": "Background color of each shimmer block",
238
261
  "fieldName": "backgroundColor"
239
262
  },
240
263
  {
264
+ "name": "duration",
241
265
  "type": {
242
266
  "text": "number"
243
267
  },
244
- "description": "Animation cycle duration in seconds",
245
- "name": "duration",
246
268
  "default": "1.5",
269
+ "description": "Animation cycle duration in seconds",
247
270
  "fieldName": "duration"
248
271
  },
249
272
  {
273
+ "name": "fallback-radius",
250
274
  "type": {
251
275
  "text": "number"
252
276
  },
253
- "description": "Border radius applied to elements with border-radius: 0 (like text)",
254
- "name": "fallback-radius",
255
277
  "default": "4",
278
+ "description": "Border radius applied to elements with border-radius: 0 (like text)",
256
279
  "fieldName": "fallbackRadius"
257
280
  },
258
281
  {
282
+ "name": "animation",
259
283
  "type": {
260
284
  "text": "Animation"
261
285
  },
262
- "description": "Animation mode: \"shimmer\" (gradient sweep), \"pulse\" (opacity), \"breathe\" (scale + fade), or \"solid\" (static)",
263
- "name": "animation",
264
286
  "default": "\"shimmer\"",
287
+ "description": "Animation mode: \"shimmer\" (gradient sweep), \"pulse\" (opacity), \"breathe\" (scale + fade), or \"solid\" (static)",
265
288
  "fieldName": "animation"
266
289
  },
267
290
  {
291
+ "name": "stagger",
268
292
  "type": {
269
293
  "text": "number"
270
294
  },
271
- "description": "Delay in seconds between each block's animation start (0 = no stagger)",
272
- "name": "stagger",
273
295
  "default": "0",
296
+ "description": "Delay in seconds between each block's animation start (0 = no stagger)",
274
297
  "fieldName": "stagger"
275
298
  },
276
299
  {
300
+ "name": "reveal",
277
301
  "type": {
278
302
  "text": "number"
279
303
  },
280
- "description": "Fade-out duration in seconds when loading ends (0 = instant)",
281
- "name": "reveal",
282
304
  "default": "0",
305
+ "description": "Fade-out duration in seconds when loading ends (0 = instant)",
283
306
  "fieldName": "reveal"
307
+ },
308
+ {
309
+ "name": "count",
310
+ "type": {
311
+ "text": "number"
312
+ },
313
+ "default": "1",
314
+ "description": "Number of skeleton rows to generate from a single template element",
315
+ "fieldName": "count"
316
+ },
317
+ {
318
+ "name": "count-gap",
319
+ "type": {
320
+ "text": "number"
321
+ },
322
+ "default": "0",
323
+ "description": "Gap in pixels between each repeated skeleton row (only used when count > 1)",
324
+ "fieldName": "countGap"
284
325
  }
285
326
  ],
286
327
  "superclass": {
@@ -1,9 +1,10 @@
1
- "use strict";(()=>{var Tt=Object.defineProperty;var Rt=Object.getOwnPropertyDescriptor;var m=(i,t,e,s)=>{for(var r=s>1?void 0:s?Rt(t,e):t,o=i.length-1,n;o>=0;o--)(n=i[o])&&(r=(s?n(t,e,r):n(r))||r);return s&&r&&Tt(t,e,r),r};var H=globalThis,I=H.ShadowRoot&&(H.ShadyCSS===void 0||H.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,V=Symbol(),it=new WeakMap,C=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==V)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o,e=this.t;if(I&&t===void 0){let s=e!==void 0&&e.length===1;s&&(t=it.get(e)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),s&&it.set(e,t))}return t}toString(){return this.cssText}},ot=i=>new C(typeof i=="string"?i:i+"",void 0,V),W=(i,...t)=>{let e=i.length===1?i[0]:t.reduce((s,r,o)=>s+(n=>{if(n._$cssResult$===!0)return n.cssText;if(typeof n=="number")return n;throw Error("Value passed to 'css' function must be a 'css' function result: "+n+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+i[o+1],i[0]);return new C(e,i,V)},nt=(i,t)=>{if(I)i.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of t){let s=document.createElement("style"),r=H.litNonce;r!==void 0&&s.setAttribute("nonce",r),s.textContent=e.cssText,i.appendChild(s)}},F=I?i=>i:i=>i instanceof CSSStyleSheet?(t=>{let e="";for(let s of t.cssRules)e+=s.cssText;return ot(e)})(i):i;var{is:kt,defineProperty:Pt,getOwnPropertyDescriptor:Mt,getOwnPropertyNames:Nt,getOwnPropertySymbols:Ut,getPrototypeOf:Ht}=Object,L=globalThis,at=L.trustedTypes,It=at?at.emptyScript:"",Lt=L.reactiveElementPolyfillSupport,O=(i,t)=>i,T={toAttribute(i,t){switch(t){case Boolean:i=i?It:null;break;case Object:case Array:i=i==null?i:JSON.stringify(i)}return i},fromAttribute(i,t){let e=i;switch(t){case Boolean:e=i!==null;break;case Number:e=i===null?null:Number(i);break;case Object:case Array:try{e=JSON.parse(i)}catch{e=null}}return e}},D=(i,t)=>!kt(i,t),lt={attribute:!0,type:String,converter:T,reflect:!1,useDefault:!1,hasChanged:D};Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;var g=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=lt){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){let s=Symbol(),r=this.getPropertyDescriptor(t,s,e);r!==void 0&&Pt(this.prototype,t,r)}}static getPropertyDescriptor(t,e,s){let{get:r,set:o}=Mt(this.prototype,t)??{get(){return this[e]},set(n){this[e]=n}};return{get:r,set(n){let l=r?.call(this);o?.call(this,n),this.requestUpdate(t,l,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??lt}static _$Ei(){if(this.hasOwnProperty(O("elementProperties")))return;let t=Ht(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(O("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(O("properties"))){let e=this.properties,s=[...Nt(e),...Ut(e)];for(let r of s)this.createProperty(r,e[r])}let t=this[Symbol.metadata];if(t!==null){let e=litPropertyMetadata.get(t);if(e!==void 0)for(let[s,r]of e)this.elementProperties.set(s,r)}this._$Eh=new Map;for(let[e,s]of this.elementProperties){let r=this._$Eu(e,s);r!==void 0&&this._$Eh.set(r,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){let e=[];if(Array.isArray(t)){let s=new Set(t.flat(1/0).reverse());for(let r of s)e.unshift(F(r))}else t!==void 0&&e.push(F(t));return e}static _$Eu(t,e){let s=e.attribute;return s===!1?void 0:typeof s=="string"?s:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){let t=new Map,e=this.constructor.elementProperties;for(let s of e.keys())this.hasOwnProperty(s)&&(t.set(s,this[s]),delete this[s]);t.size>0&&(this._$Ep=t)}createRenderRoot(){let t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return nt(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,s){this._$AK(t,s)}_$ET(t,e){let s=this.constructor.elementProperties.get(t),r=this.constructor._$Eu(t,s);if(r!==void 0&&s.reflect===!0){let o=(s.converter?.toAttribute!==void 0?s.converter:T).toAttribute(e,s.type);this._$Em=t,o==null?this.removeAttribute(r):this.setAttribute(r,o),this._$Em=null}}_$AK(t,e){let s=this.constructor,r=s._$Eh.get(t);if(r!==void 0&&this._$Em!==r){let o=s.getPropertyOptions(r),n=typeof o.converter=="function"?{fromAttribute:o.converter}:o.converter?.fromAttribute!==void 0?o.converter:T;this._$Em=r;let l=n.fromAttribute(e,o.type);this[r]=l??this._$Ej?.get(r)??l,this._$Em=null}}requestUpdate(t,e,s,r=!1,o){if(t!==void 0){let n=this.constructor;if(r===!1&&(o=this[t]),s??=n.getPropertyOptions(t),!((s.hasChanged??D)(o,e)||s.useDefault&&s.reflect&&o===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,s))))return;this.C(t,e,s)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,e,{useDefault:s,reflect:r,wrapped:o},n){s&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),o!==!0||n!==void 0)||(this._$AL.has(t)||(this.hasUpdated||s||(e=void 0),this._$AL.set(t,e)),r===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[r,o]of this._$Ep)this[r]=o;this._$Ep=void 0}let s=this.constructor.elementProperties;if(s.size>0)for(let[r,o]of s){let{wrapped:n}=o,l=this[r];n!==!0||this._$AL.has(r)||l===void 0||this.C(r,void 0,o,l)}}let t=!1,e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(e)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(t){}firstUpdated(t){}};g.elementStyles=[],g.shadowRootOptions={mode:"open"},g[O("elementProperties")]=new Map,g[O("finalized")]=new Map,Lt?.({ReactiveElement:g}),(L.reactiveElementVersions??=[]).push("2.1.2");var Q=globalThis,ht=i=>i,B=Q.trustedTypes,ct=B?B.createPolicy("lit-html",{createHTML:i=>i}):void 0,_t="$lit$",y=`lit$${Math.random().toFixed(9).slice(2)}$`,gt="?"+y,Dt=`<${gt}>`,S=document,k=()=>S.createComment(""),P=i=>i===null||typeof i!="object"&&typeof i!="function",tt=Array.isArray,Bt=i=>tt(i)||typeof i?.[Symbol.iterator]=="function",K=`[
1
+ "use strict";(()=>{var Rt=Object.defineProperty;var kt=Object.getOwnPropertyDescriptor;var m=(r,t,e,s)=>{for(var i=s>1?void 0:s?kt(t,e):t,o=r.length-1,n;o>=0;o--)(n=r[o])&&(i=(s?n(t,e,i):n(i))||i);return s&&i&&Rt(t,e,i),i};var U=globalThis,L=U.ShadowRoot&&(U.ShadyCSS===void 0||U.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,V=Symbol(),rt=new WeakMap,w=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==V)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o,e=this.t;if(L&&t===void 0){let s=e!==void 0&&e.length===1;s&&(t=rt.get(e)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),s&&rt.set(e,t))}return t}toString(){return this.cssText}},ot=r=>new w(typeof r=="string"?r:r+"",void 0,V),W=(r,...t)=>{let e=r.length===1?r[0]:t.reduce((s,i,o)=>s+(n=>{if(n._$cssResult$===!0)return n.cssText;if(typeof n=="number")return n;throw Error("Value passed to 'css' function must be a 'css' function result: "+n+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+r[o+1],r[0]);return new w(e,r,V)},nt=(r,t)=>{if(L)r.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of t){let s=document.createElement("style"),i=U.litNonce;i!==void 0&&s.setAttribute("nonce",i),s.textContent=e.cssText,r.appendChild(s)}},G=L?r=>r:r=>r instanceof CSSStyleSheet?(t=>{let e="";for(let s of t.cssRules)e+=s.cssText;return ot(e)})(r):r;var{is:Mt,defineProperty:Nt,getOwnPropertyDescriptor:Pt,getOwnPropertyNames:Ht,getOwnPropertySymbols:Ut,getPrototypeOf:Lt}=Object,I=globalThis,at=I.trustedTypes,It=at?at.emptyScript:"",Dt=I.reactiveElementPolyfillSupport,T=(r,t)=>r,O={toAttribute(r,t){switch(t){case Boolean:r=r?It:null;break;case Object:case Array:r=r==null?r:JSON.stringify(r)}return r},fromAttribute(r,t){let e=r;switch(t){case Boolean:e=r!==null;break;case Number:e=r===null?null:Number(r);break;case Object:case Array:try{e=JSON.parse(r)}catch{e=null}}return e}},D=(r,t)=>!Mt(r,t),lt={attribute:!0,type:String,converter:O,reflect:!1,useDefault:!1,hasChanged:D};Symbol.metadata??=Symbol("metadata"),I.litPropertyMetadata??=new WeakMap;var _=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=lt){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){let s=Symbol(),i=this.getPropertyDescriptor(t,s,e);i!==void 0&&Nt(this.prototype,t,i)}}static getPropertyDescriptor(t,e,s){let{get:i,set:o}=Pt(this.prototype,t)??{get(){return this[e]},set(n){this[e]=n}};return{get:i,set(n){let l=i?.call(this);o?.call(this,n),this.requestUpdate(t,l,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??lt}static _$Ei(){if(this.hasOwnProperty(T("elementProperties")))return;let t=Lt(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(T("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(T("properties"))){let e=this.properties,s=[...Ht(e),...Ut(e)];for(let i of s)this.createProperty(i,e[i])}let t=this[Symbol.metadata];if(t!==null){let e=litPropertyMetadata.get(t);if(e!==void 0)for(let[s,i]of e)this.elementProperties.set(s,i)}this._$Eh=new Map;for(let[e,s]of this.elementProperties){let i=this._$Eu(e,s);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){let e=[];if(Array.isArray(t)){let s=new Set(t.flat(1/0).reverse());for(let i of s)e.unshift(G(i))}else t!==void 0&&e.push(G(t));return e}static _$Eu(t,e){let s=e.attribute;return s===!1?void 0:typeof s=="string"?s:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){let t=new Map,e=this.constructor.elementProperties;for(let s of e.keys())this.hasOwnProperty(s)&&(t.set(s,this[s]),delete this[s]);t.size>0&&(this._$Ep=t)}createRenderRoot(){let t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return nt(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,s){this._$AK(t,s)}_$ET(t,e){let s=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,s);if(i!==void 0&&s.reflect===!0){let o=(s.converter?.toAttribute!==void 0?s.converter:O).toAttribute(e,s.type);this._$Em=t,o==null?this.removeAttribute(i):this.setAttribute(i,o),this._$Em=null}}_$AK(t,e){let s=this.constructor,i=s._$Eh.get(t);if(i!==void 0&&this._$Em!==i){let o=s.getPropertyOptions(i),n=typeof o.converter=="function"?{fromAttribute:o.converter}:o.converter?.fromAttribute!==void 0?o.converter:O;this._$Em=i;let l=n.fromAttribute(e,o.type);this[i]=l??this._$Ej?.get(i)??l,this._$Em=null}}requestUpdate(t,e,s,i=!1,o){if(t!==void 0){let n=this.constructor;if(i===!1&&(o=this[t]),s??=n.getPropertyOptions(t),!((s.hasChanged??D)(o,e)||s.useDefault&&s.reflect&&o===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,s))))return;this.C(t,e,s)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,e,{useDefault:s,reflect:i,wrapped:o},n){s&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),o!==!0||n!==void 0)||(this._$AL.has(t)||(this.hasUpdated||s||(e=void 0),this._$AL.set(t,e)),i===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[i,o]of this._$Ep)this[i]=o;this._$Ep=void 0}let s=this.constructor.elementProperties;if(s.size>0)for(let[i,o]of s){let{wrapped:n}=o,l=this[i];n!==!0||this._$AL.has(i)||l===void 0||this.C(i,void 0,o,l)}}let t=!1,e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(e)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(t){}firstUpdated(t){}};_.elementStyles=[],_.shadowRootOptions={mode:"open"},_[T("elementProperties")]=new Map,_[T("finalized")]=new Map,Dt?.({ReactiveElement:_}),(I.reactiveElementVersions??=[]).push("2.1.2");var Q=globalThis,ht=r=>r,B=Q.trustedTypes,ct=B?B.createPolicy("lit-html",{createHTML:r=>r}):void 0,gt="$lit$",$=`lit$${Math.random().toFixed(9).slice(2)}$`,_t="?"+$,Bt=`<${_t}>`,S=document,k=()=>S.createComment(""),M=r=>r===null||typeof r!="object"&&typeof r!="function",tt=Array.isArray,jt=r=>tt(r)||typeof r?.[Symbol.iterator]=="function",K=`[
2
2
  \f\r]`,R=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,dt=/-->/g,ut=/>/g,A=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^
3
- \f\r"'\`<>=]|("|')|))|$)`,"g"),pt=/'/g,mt=/"/g,$t=/^(?:script|style|textarea|title)$/i,et=i=>(t,...e)=>({_$litType$:i,strings:t,values:e}),z=et(1),se=et(2),re=et(3),$=Symbol.for("lit-noChange"),u=Symbol.for("lit-nothing"),ft=new WeakMap,E=S.createTreeWalker(S,129);function vt(i,t){if(!tt(i)||!i.hasOwnProperty("raw"))throw Error("invalid template strings array");return ct!==void 0?ct.createHTML(t):t}var zt=(i,t)=>{let e=i.length-1,s=[],r,o=t===2?"<svg>":t===3?"<math>":"",n=R;for(let l=0;l<e;l++){let a=i[l],h,d,c=-1,_=0;for(;_<a.length&&(n.lastIndex=_,d=n.exec(a),d!==null);)_=n.lastIndex,n===R?d[1]==="!--"?n=dt:d[1]!==void 0?n=ut:d[2]!==void 0?($t.test(d[2])&&(r=RegExp("</"+d[2],"g")),n=A):d[3]!==void 0&&(n=A):n===A?d[0]===">"?(n=r??R,c=-1):d[1]===void 0?c=-2:(c=n.lastIndex-d[2].length,h=d[1],n=d[3]===void 0?A:d[3]==='"'?mt:pt):n===mt||n===pt?n=A:n===dt||n===ut?n=R:(n=A,r=void 0);let v=n===A&&i[l+1].startsWith("/>")?" ":"";o+=n===R?a+Dt:c>=0?(s.push(h),a.slice(0,c)+_t+a.slice(c)+y+v):a+y+(c===-2?l:v)}return[vt(i,o+(i[e]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),s]},M=class i{constructor({strings:t,_$litType$:e},s){let r;this.parts=[];let o=0,n=0,l=t.length-1,a=this.parts,[h,d]=zt(t,e);if(this.el=i.createElement(h,s),E.currentNode=this.el.content,e===2||e===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(r=E.nextNode())!==null&&a.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let c of r.getAttributeNames())if(c.endsWith(_t)){let _=d[n++],v=r.getAttribute(c).split(y),U=/([.?@])?(.*)/.exec(_);a.push({type:1,index:o,name:U[2],strings:v,ctor:U[1]==="."?J:U[1]==="?"?X:U[1]==="@"?Y:w}),r.removeAttribute(c)}else c.startsWith(y)&&(a.push({type:6,index:o}),r.removeAttribute(c));if($t.test(r.tagName)){let c=r.textContent.split(y),_=c.length-1;if(_>0){r.textContent=B?B.emptyScript:"";for(let v=0;v<_;v++)r.append(c[v],k()),E.nextNode(),a.push({type:2,index:++o});r.append(c[_],k())}}}else if(r.nodeType===8)if(r.data===gt)a.push({type:2,index:o});else{let c=-1;for(;(c=r.data.indexOf(y,c+1))!==-1;)a.push({type:7,index:o}),c+=y.length-1}o++}}static createElement(t,e){let s=S.createElement("template");return s.innerHTML=t,s}};function x(i,t,e=i,s){if(t===$)return t;let r=s!==void 0?e._$Co?.[s]:e._$Cl,o=P(t)?void 0:t._$litDirective$;return r?.constructor!==o&&(r?._$AO?.(!1),o===void 0?r=void 0:(r=new o(i),r._$AT(i,e,s)),s!==void 0?(e._$Co??=[])[s]=r:e._$Cl=r),r!==void 0&&(t=x(i,r._$AS(i,t.values),r,s)),t}var G=class{constructor(t,e){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){let{el:{content:e},parts:s}=this._$AD,r=(t?.creationScope??S).importNode(e,!0);E.currentNode=r;let o=E.nextNode(),n=0,l=0,a=s[0];for(;a!==void 0;){if(n===a.index){let h;a.type===2?h=new N(o,o.nextSibling,this,t):a.type===1?h=new a.ctor(o,a.name,a.strings,this,t):a.type===6&&(h=new Z(o,this,t)),this._$AV.push(h),a=s[++l]}n!==a?.index&&(o=E.nextNode(),n++)}return E.currentNode=S,r}p(t){let e=0;for(let s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(t,s,e),e+=s.strings.length-2):s._$AI(t[e])),e++}},N=class i{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,e,s,r){this.type=2,this._$AH=u,this._$AN=void 0,this._$AA=t,this._$AB=e,this._$AM=s,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode,e=this._$AM;return e!==void 0&&t?.nodeType===11&&(t=e.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,e=this){t=x(this,t,e),P(t)?t===u||t==null||t===""?(this._$AH!==u&&this._$AR(),this._$AH=u):t!==this._$AH&&t!==$&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):Bt(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==u&&P(this._$AH)?this._$AA.nextSibling.data=t:this.T(S.createTextNode(t)),this._$AH=t}$(t){let{values:e,_$litType$:s}=t,r=typeof s=="number"?this._$AC(t):(s.el===void 0&&(s.el=M.createElement(vt(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===r)this._$AH.p(e);else{let o=new G(r,this),n=o.u(this.options);o.p(e),this.T(n),this._$AH=o}}_$AC(t){let e=ft.get(t.strings);return e===void 0&&ft.set(t.strings,e=new M(t)),e}k(t){tt(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,s,r=0;for(let o of t)r===e.length?e.push(s=new i(this.O(k()),this.O(k()),this,this.options)):s=e[r],s._$AI(o),r++;r<e.length&&(this._$AR(s&&s._$AB.nextSibling,r),e.length=r)}_$AR(t=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);t!==this._$AB;){let s=ht(t).nextSibling;ht(t).remove(),t=s}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}},w=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,e,s,r,o){this.type=1,this._$AH=u,this._$AN=void 0,this.element=t,this.name=e,this._$AM=r,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=u}_$AI(t,e=this,s,r){let o=this.strings,n=!1;if(o===void 0)t=x(this,t,e,0),n=!P(t)||t!==this._$AH&&t!==$,n&&(this._$AH=t);else{let l=t,a,h;for(t=o[0],a=0;a<o.length-1;a++)h=x(this,l[s+a],e,a),h===$&&(h=this._$AH[a]),n||=!P(h)||h!==this._$AH[a],h===u?t=u:t!==u&&(t+=(h??"")+o[a+1]),this._$AH[a]=h}n&&!r&&this.j(t)}j(t){t===u?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}},J=class extends w{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===u?void 0:t}},X=class extends w{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==u)}},Y=class extends w{constructor(t,e,s,r,o){super(t,e,s,r,o),this.type=5}_$AI(t,e=this){if((t=x(this,t,e,0)??u)===$)return;let s=this._$AH,r=t===u&&s!==u||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,o=t!==u&&(s===u||r);r&&this.element.removeEventListener(this.name,this,s),o&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}},Z=class{constructor(t,e,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=e,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){x(this,t)}};var jt=Q.litHtmlPolyfillSupport;jt?.(M,N),(Q.litHtmlVersions??=[]).push("3.3.2");var yt=(i,t,e)=>{let s=e?.renderBefore??t,r=s._$litPart$;if(r===void 0){let o=e?.renderBefore??null;s._$litPart$=r=new N(t.insertBefore(k(),o),o,void 0,e??{})}return r._$AI(i),r};var st=globalThis,b=class extends g{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){let e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=yt(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return $}};b._$litElement$=!0,b.finalized=!0,st.litElementHydrateSupport?.({LitElement:b});var qt=st.litElementPolyfillSupport;qt?.({LitElement:b});(st.litElementVersions??=[]).push("4.2.2");var bt=i=>(t,e)=>{e!==void 0?e.addInitializer(()=>{customElements.define(i,t)}):customElements.define(i,t)};var Vt={attribute:!0,type:String,converter:T,reflect:!1,hasChanged:D},Wt=(i=Vt,t,e)=>{let{kind:s,metadata:r}=e,o=globalThis.litPropertyMetadata.get(r);if(o===void 0&&globalThis.litPropertyMetadata.set(r,o=new Map),s==="setter"&&((i=Object.create(i)).wrapped=!0),o.set(e.name,i),s==="accessor"){let{name:n}=e;return{set(l){let a=t.get.call(this);t.set.call(this,l),this.requestUpdate(n,a,i,!0,l)},init(l){return l!==void 0&&this.C(n,void 0,i,l),l}}}if(s==="setter"){let{name:n}=e;return function(l){let a=this[n];t.call(this,l),this.requestUpdate(n,a,i,!0,l)}}throw Error("Unsupported decorator location: "+s)};function f(i){return(t,e)=>typeof e=="object"?Wt(i,t,e):((s,r,o)=>{let n=r.hasOwnProperty(o);return r.constructor.createProperty(o,s),n?Object.getOwnPropertyDescriptor(r,o):void 0})(i,t,e)}function rt(i){return f({...i,state:!0,attribute:!1})}var At={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},Et=i=>(...t)=>({_$litDirective$:i,values:t}),q=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,s){this._$Ct=t,this._$AM=e,this._$Ci=s}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};var St="important",Ft=" !"+St,xt=Et(class extends q{constructor(i){if(super(i),i.type!==At.ATTRIBUTE||i.name!=="style"||i.strings?.length>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.")}render(i){return Object.keys(i).reduce((t,e)=>{let s=i[e];return s==null?t:t+`${e=e.includes("-")?e:e.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-$&").toLowerCase()}:${s};`},"")}update(i,[t]){let{style:e}=i.element;if(this.ft===void 0)return this.ft=new Set(Object.keys(t)),this.render(t);for(let s of this.ft)t[s]==null&&(this.ft.delete(s),s.includes("-")?e.removeProperty(s):e[s]=null);for(let s in t){let r=t[s];if(r!=null){this.ft.add(s);let o=typeof r=="string"&&r.endsWith(Ft);s.includes("-")||o?e.setProperty(s,o?r.slice(0,-11):r,o?St:""):e[s]=r}}return $}});var Kt=new Set(["IMG","SVG","VIDEO","CANVAS","IFRAME","INPUT","TEXTAREA","BUTTON","HR"]),Gt=new Set(["BR","WBR","HR"]);function Jt(i){if(Kt.has(i.tagName))return!0;for(let t of i.children)if(!Gt.has(t.tagName))return!1;return!0}function Xt(i){for(let t of i.childNodes)if(t.nodeType===Node.TEXT_NODE&&t.textContent?.trim())return!0;return!1}function wt(i,t){let e=[];function s(r){let o=r.getBoundingClientRect();if(o.width===0||o.height===0||r.hasAttribute("data-shimmer-ignore"))return;if(r.hasAttribute("data-shimmer-no-children")||Jt(r)){let a=getComputedStyle(r).borderRadius;if((r.tagName==="TD"||r.tagName==="TH")&&Xt(r)){let h=document.createElement("span");h.style.visibility="hidden",h.style.position="absolute",h.textContent=r.textContent,r.appendChild(h);let d=h.getBoundingClientRect();r.removeChild(h),e.push({x:o.left-t.left,y:o.top-t.top,width:Math.min(d.width,o.width),height:o.height,tag:r.tagName.toLowerCase(),borderRadius:a==="0px"?"":a});return}e.push({x:o.left-t.left,y:o.top-t.top,width:o.width,height:o.height,tag:r.tagName.toLowerCase(),borderRadius:a==="0px"?"":a});return}for(let l of r.children)s(l)}return s(i),e}function Ct(i,t){let e=null,s=new ResizeObserver(()=>{e!==null&&cancelAnimationFrame(e),e=requestAnimationFrame(()=>{e=null,t()})});return s.observe(i),s}var Ot=W`
3
+ \f\r"'\`<>=]|("|')|))|$)`,"g"),pt=/'/g,mt=/"/g,vt=/^(?:script|style|textarea|title)$/i,et=r=>(t,...e)=>({_$litType$:r,strings:t,values:e}),j=et(1),re=et(2),oe=et(3),v=Symbol.for("lit-noChange"),u=Symbol.for("lit-nothing"),ft=new WeakMap,E=S.createTreeWalker(S,129);function yt(r,t){if(!tt(r)||!r.hasOwnProperty("raw"))throw Error("invalid template strings array");return ct!==void 0?ct.createHTML(t):t}var zt=(r,t)=>{let e=r.length-1,s=[],i,o=t===2?"<svg>":t===3?"<math>":"",n=R;for(let l=0;l<e;l++){let a=r[l],h,d,c=-1,g=0;for(;g<a.length&&(n.lastIndex=g,d=n.exec(a),d!==null);)g=n.lastIndex,n===R?d[1]==="!--"?n=dt:d[1]!==void 0?n=ut:d[2]!==void 0?(vt.test(d[2])&&(i=RegExp("</"+d[2],"g")),n=A):d[3]!==void 0&&(n=A):n===A?d[0]===">"?(n=i??R,c=-1):d[1]===void 0?c=-2:(c=n.lastIndex-d[2].length,h=d[1],n=d[3]===void 0?A:d[3]==='"'?mt:pt):n===mt||n===pt?n=A:n===dt||n===ut?n=R:(n=A,i=void 0);let y=n===A&&r[l+1].startsWith("/>")?" ":"";o+=n===R?a+Bt:c>=0?(s.push(h),a.slice(0,c)+gt+a.slice(c)+$+y):a+$+(c===-2?l:y)}return[yt(r,o+(r[e]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),s]},N=class r{constructor({strings:t,_$litType$:e},s){let i;this.parts=[];let o=0,n=0,l=t.length-1,a=this.parts,[h,d]=zt(t,e);if(this.el=r.createElement(h,s),E.currentNode=this.el.content,e===2||e===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(i=E.nextNode())!==null&&a.length<l;){if(i.nodeType===1){if(i.hasAttributes())for(let c of i.getAttributeNames())if(c.endsWith(gt)){let g=d[n++],y=i.getAttribute(c).split($),H=/([.?@])?(.*)/.exec(g);a.push({type:1,index:o,name:H[2],strings:y,ctor:H[1]==="."?J:H[1]==="?"?X:H[1]==="@"?Y:C}),i.removeAttribute(c)}else c.startsWith($)&&(a.push({type:6,index:o}),i.removeAttribute(c));if(vt.test(i.tagName)){let c=i.textContent.split($),g=c.length-1;if(g>0){i.textContent=B?B.emptyScript:"";for(let y=0;y<g;y++)i.append(c[y],k()),E.nextNode(),a.push({type:2,index:++o});i.append(c[g],k())}}}else if(i.nodeType===8)if(i.data===_t)a.push({type:2,index:o});else{let c=-1;for(;(c=i.data.indexOf($,c+1))!==-1;)a.push({type:7,index:o}),c+=$.length-1}o++}}static createElement(t,e){let s=S.createElement("template");return s.innerHTML=t,s}};function x(r,t,e=r,s){if(t===v)return t;let i=s!==void 0?e._$Co?.[s]:e._$Cl,o=M(t)?void 0:t._$litDirective$;return i?.constructor!==o&&(i?._$AO?.(!1),o===void 0?i=void 0:(i=new o(r),i._$AT(r,e,s)),s!==void 0?(e._$Co??=[])[s]=i:e._$Cl=i),i!==void 0&&(t=x(r,i._$AS(r,t.values),i,s)),t}var F=class{constructor(t,e){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){let{el:{content:e},parts:s}=this._$AD,i=(t?.creationScope??S).importNode(e,!0);E.currentNode=i;let o=E.nextNode(),n=0,l=0,a=s[0];for(;a!==void 0;){if(n===a.index){let h;a.type===2?h=new P(o,o.nextSibling,this,t):a.type===1?h=new a.ctor(o,a.name,a.strings,this,t):a.type===6&&(h=new Z(o,this,t)),this._$AV.push(h),a=s[++l]}n!==a?.index&&(o=E.nextNode(),n++)}return E.currentNode=S,i}p(t){let e=0;for(let s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(t,s,e),e+=s.strings.length-2):s._$AI(t[e])),e++}},P=class r{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,e,s,i){this.type=2,this._$AH=u,this._$AN=void 0,this._$AA=t,this._$AB=e,this._$AM=s,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode,e=this._$AM;return e!==void 0&&t?.nodeType===11&&(t=e.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,e=this){t=x(this,t,e),M(t)?t===u||t==null||t===""?(this._$AH!==u&&this._$AR(),this._$AH=u):t!==this._$AH&&t!==v&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):jt(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==u&&M(this._$AH)?this._$AA.nextSibling.data=t:this.T(S.createTextNode(t)),this._$AH=t}$(t){let{values:e,_$litType$:s}=t,i=typeof s=="number"?this._$AC(t):(s.el===void 0&&(s.el=N.createElement(yt(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===i)this._$AH.p(e);else{let o=new F(i,this),n=o.u(this.options);o.p(e),this.T(n),this._$AH=o}}_$AC(t){let e=ft.get(t.strings);return e===void 0&&ft.set(t.strings,e=new N(t)),e}k(t){tt(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,s,i=0;for(let o of t)i===e.length?e.push(s=new r(this.O(k()),this.O(k()),this,this.options)):s=e[i],s._$AI(o),i++;i<e.length&&(this._$AR(s&&s._$AB.nextSibling,i),e.length=i)}_$AR(t=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);t!==this._$AB;){let s=ht(t).nextSibling;ht(t).remove(),t=s}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}},C=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,e,s,i,o){this.type=1,this._$AH=u,this._$AN=void 0,this.element=t,this.name=e,this._$AM=i,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=u}_$AI(t,e=this,s,i){let o=this.strings,n=!1;if(o===void 0)t=x(this,t,e,0),n=!M(t)||t!==this._$AH&&t!==v,n&&(this._$AH=t);else{let l=t,a,h;for(t=o[0],a=0;a<o.length-1;a++)h=x(this,l[s+a],e,a),h===v&&(h=this._$AH[a]),n||=!M(h)||h!==this._$AH[a],h===u?t=u:t!==u&&(t+=(h??"")+o[a+1]),this._$AH[a]=h}n&&!i&&this.j(t)}j(t){t===u?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}},J=class extends C{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===u?void 0:t}},X=class extends C{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==u)}},Y=class extends C{constructor(t,e,s,i,o){super(t,e,s,i,o),this.type=5}_$AI(t,e=this){if((t=x(this,t,e,0)??u)===v)return;let s=this._$AH,i=t===u&&s!==u||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,o=t!==u&&(s===u||i);i&&this.element.removeEventListener(this.name,this,s),o&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}},Z=class{constructor(t,e,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=e,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){x(this,t)}};var qt=Q.litHtmlPolyfillSupport;qt?.(N,P),(Q.litHtmlVersions??=[]).push("3.3.2");var $t=(r,t,e)=>{let s=e?.renderBefore??t,i=s._$litPart$;if(i===void 0){let o=e?.renderBefore??null;s._$litPart$=i=new P(t.insertBefore(k(),o),o,void 0,e??{})}return i._$AI(r),i};var st=globalThis,b=class extends _{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){let e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=$t(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return v}};b._$litElement$=!0,b.finalized=!0,st.litElementHydrateSupport?.({LitElement:b});var Vt=st.litElementPolyfillSupport;Vt?.({LitElement:b});(st.litElementVersions??=[]).push("4.2.2");var bt=r=>(t,e)=>{e!==void 0?e.addInitializer(()=>{customElements.define(r,t)}):customElements.define(r,t)};var Wt={attribute:!0,type:String,converter:O,reflect:!1,hasChanged:D},Gt=(r=Wt,t,e)=>{let{kind:s,metadata:i}=e,o=globalThis.litPropertyMetadata.get(i);if(o===void 0&&globalThis.litPropertyMetadata.set(i,o=new Map),s==="setter"&&((r=Object.create(r)).wrapped=!0),o.set(e.name,r),s==="accessor"){let{name:n}=e;return{set(l){let a=t.get.call(this);t.set.call(this,l),this.requestUpdate(n,a,r,!0,l)},init(l){return l!==void 0&&this.C(n,void 0,r,l),l}}}if(s==="setter"){let{name:n}=e;return function(l){let a=this[n];t.call(this,l),this.requestUpdate(n,a,r,!0,l)}}throw Error("Unsupported decorator location: "+s)};function f(r){return(t,e)=>typeof e=="object"?Gt(r,t,e):((s,i,o)=>{let n=i.hasOwnProperty(o);return i.constructor.createProperty(o,s),n?Object.getOwnPropertyDescriptor(i,o):void 0})(r,t,e)}function it(r){return f({...r,state:!0,attribute:!1})}var At={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},Et=r=>(...t)=>({_$litDirective$:r,values:t}),q=class{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,s){this._$Ct=t,this._$AM=e,this._$Ci=s}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}};var St="important",Kt=" !"+St,xt=Et(class extends q{constructor(r){if(super(r),r.type!==At.ATTRIBUTE||r.name!=="style"||r.strings?.length>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.")}render(r){return Object.keys(r).reduce((t,e)=>{let s=r[e];return s==null?t:t+`${e=e.includes("-")?e:e.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-$&").toLowerCase()}:${s};`},"")}update(r,[t]){let{style:e}=r.element;if(this.ft===void 0)return this.ft=new Set(Object.keys(t)),this.render(t);for(let s of this.ft)t[s]==null&&(this.ft.delete(s),s.includes("-")?e.removeProperty(s):e[s]=null);for(let s in t){let i=t[s];if(i!=null){this.ft.add(s);let o=typeof i=="string"&&i.endsWith(Kt);s.includes("-")||o?e.setProperty(s,o?i.slice(0,-11):i,o?St:""):e[s]=i}}return v}});var Ft=new Set(["IMG","SVG","VIDEO","CANVAS","IFRAME","INPUT","TEXTAREA","BUTTON","HR"]),Jt=new Set(["BR","WBR","HR"]);function Xt(r){if(Ft.has(r.tagName))return!0;for(let t of r.children)if(!Jt.has(t.tagName))return!1;return!0}function Yt(r){for(let t of r.childNodes)if(t.nodeType===Node.TEXT_NODE&&t.textContent?.trim())return!0;return!1}function Ct(r,t){let e=[];function s(i){let o=i.getBoundingClientRect();if(o.width===0||o.height===0||i.hasAttribute("data-shimmer-ignore"))return;if(i.hasAttribute("data-shimmer-no-children")||Xt(i)){let a=getComputedStyle(i).borderRadius;if((i.tagName==="TD"||i.tagName==="TH")&&Yt(i)){let h=document.createElement("span");h.style.visibility="hidden",h.style.position="absolute",h.textContent=i.textContent,i.appendChild(h);let d=h.getBoundingClientRect();i.removeChild(h),e.push({x:o.left-t.left,y:o.top-t.top,width:Math.min(d.width,o.width),height:o.height,tag:i.tagName.toLowerCase(),borderRadius:a==="0px"?"":a});return}e.push({x:o.left-t.left,y:o.top-t.top,width:o.width,height:o.height,tag:i.tagName.toLowerCase(),borderRadius:a==="0px"?"":a});return}for(let l of i.children)s(l)}return s(r),e}function wt(r,t){let e=null,s=new ResizeObserver(()=>{e!==null&&cancelAnimationFrame(e),e=requestAnimationFrame(()=>{e=null,t()})});return s.observe(r),s}var Tt=W`
4
4
  :host {
5
5
  display: block;
6
6
  position: relative;
7
+ overflow: hidden;
7
8
  --shimmer-color: rgba(255, 255, 255, 0.3);
8
9
  --shimmer-duration: 1.5s;
9
10
  --shimmer-bg: rgba(255, 255, 255, 0.08);
@@ -108,9 +109,22 @@
108
109
  :host([animation="solid"]) .shimmer-block::after {
109
110
  display: none;
110
111
  }
111
- `;var p=class extends b{constructor(){super(...arguments);this.loading=!1;this.shimmerColor="rgba(255, 255, 255, 0.3)";this.backgroundColor="rgba(255, 255, 255, 0.08)";this.duration=1.5;this.fallbackRadius=4;this.animation="shimmer";this.stagger=0;this.reveal=0;this._blocks=[];this._revealing=!1;this._resizeObserver=null;this._mutationObserver=null;this._measureScheduled=!1;this._revealTimeout=null}disconnectedCallback(){super.disconnectedCallback(),this._teardownObservers(),this._clearRevealTimeout()}updated(e){e.has("loading")&&(this.setAttribute("aria-busy",String(this.loading)),this.loading?(this._revealing=!1,this._clearRevealTimeout(),this._scheduleMeasure(),this._setupObservers()):this.reveal>0&&this._blocks.length>0?(this._revealing=!0,this._teardownObservers(),this._revealTimeout=setTimeout(()=>{this._revealing=!1,this._blocks=[],this._revealTimeout=null},this.reveal*1e3)):(this._blocks=[],this._teardownObservers()))}render(){let e=xt({"--shimmer-color":this.shimmerColor,"--shimmer-duration":`${this.duration}s`,"--shimmer-bg":this.backgroundColor,"--reveal-duration":`${this.reveal}s`}),s=this.loading||this._revealing;return z`
112
+ `;var Ot="phantom-ui-loading-styles";function Zt(){if(document.getElementById(Ot))return;let r=document.createElement("style");r.id=Ot,r.textContent=`
113
+ phantom-ui[loading] * {
114
+ color: transparent !important;
115
+ -webkit-text-fill-color: transparent !important;
116
+ pointer-events: none;
117
+ user-select: none;
118
+ }
119
+ phantom-ui[loading] img,
120
+ phantom-ui[loading] svg,
121
+ phantom-ui[loading] video,
122
+ phantom-ui[loading] canvas {
123
+ opacity: 0 !important;
124
+ }
125
+ `,document.head.appendChild(r)}var p=class extends b{constructor(){super(...arguments);this.loading=!1;this.shimmerColor="rgba(255, 255, 255, 0.3)";this.backgroundColor="rgba(255, 255, 255, 0.08)";this.duration=1.5;this.fallbackRadius=4;this.animation="shimmer";this.stagger=0;this.reveal=0;this.count=1;this.countGap=0;this._blocks=[];this._revealing=!1;this._resizeObserver=null;this._mutationObserver=null;this._loadHandler=null;this._measureScheduled=!1;this._revealTimeout=null}connectedCallback(){super.connectedCallback(),Zt()}disconnectedCallback(){super.disconnectedCallback(),this._teardownObservers(),this._clearRevealTimeout()}willUpdate(e){e.has("loading")&&!this.loading&&this.reveal>0&&this._blocks.length>0&&(this._revealing=!0)}updated(e){(e.has("count")||e.has("countGap"))&&this.loading&&this._scheduleMeasure(),e.has("loading")&&(this.setAttribute("aria-busy",String(this.loading)),this.loading?(this._revealing=!1,this._clearRevealTimeout(),this._scheduleMeasure(),this._setupObservers()):this._revealing?(this._teardownObservers(),this._revealTimeout=setTimeout(()=>{this._revealing=!1,this._blocks=[],this._revealTimeout=null,this.style.minHeight=""},this.reveal*1e3)):(this._blocks=[],this._teardownObservers(),this.style.minHeight=""))}render(){let e=xt({"--shimmer-color":this.shimmerColor,"--shimmer-duration":`${this.duration}s`,"--shimmer-bg":this.backgroundColor,"--reveal-duration":`${this.reveal}s`}),s=this.loading||this._revealing;return j`
112
126
  <slot></slot>
113
- ${s?z`
127
+ ${s?j`
114
128
  <div
115
129
  class="shimmer-overlay ${this._revealing?"revealing":""}"
116
130
  style=${e}
@@ -119,7 +133,7 @@
119
133
  ${this._renderBlocks()}
120
134
  </div>
121
135
  `:""}
122
- `}_scheduleMeasure(){this._measureScheduled||(this._measureScheduled=!0,requestAnimationFrame(()=>{this._measureScheduled=!1,this._measure()}))}_measure(){if(!this.loading)return;let e=this.getBoundingClientRect();if(e.width===0||e.height===0)return;let s=this.shadowRoot?.querySelector("slot");if(!s)return;let r=s.assignedElements({flatten:!0}),o=[];for(let n of r){let l=wt(n,e);o.push(...l)}this._blocks=o}_setupObservers(){this._teardownObservers(),this._resizeObserver=Ct(this,()=>{this._scheduleMeasure()}),this._mutationObserver=new MutationObserver(()=>{this._scheduleMeasure()}),this._mutationObserver.observe(this,{childList:!0,subtree:!0,attributes:!0})}_teardownObservers(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null)}_clearRevealTimeout(){this._revealTimeout!==null&&(clearTimeout(this._revealTimeout),this._revealTimeout=null)}_renderBlocks(){return this._blocks.map((e,s)=>{let r=e.borderRadius||`${this.fallbackRadius}px`,o=this.stagger,n=o>0?`animation-delay: ${s*o}s;`:"";return z`
136
+ `}_scheduleMeasure(){this._measureScheduled||(this._measureScheduled=!0,requestAnimationFrame(()=>{this._measureScheduled=!1,this._measure()}))}_measure(){if(!this.loading)return;let e=this.getBoundingClientRect();if(e.width===0||e.height===0)return;let s=this.shadowRoot?.querySelector("slot");if(!s)return;let i=s.assignedElements({flatten:!0}),o=[];for(let n of i){let l=Ct(n,e);o.push(...l)}if(this.count>1&&o.length>0){let n=0;for(let h of i){let d=h.getBoundingClientRect();n=Math.max(n,d.bottom-e.top)}let l=[...o];for(let h=1;h<this.count;h++)for(let d of l)o.push({...d,y:d.y+h*(n+this.countGap)});let a=this.count*n+(this.count-1)*this.countGap;this.style.minHeight=`${a}px`}else this.style.minHeight="";this._blocks=o}_setupObservers(){this._teardownObservers(),this._resizeObserver=wt(this,()=>{this._scheduleMeasure()}),this._mutationObserver=new MutationObserver(()=>{this._scheduleMeasure()}),this._mutationObserver.observe(this,{childList:!0,subtree:!0,attributes:!0}),this._loadHandler=()=>this._scheduleMeasure(),this.addEventListener("load",this._loadHandler,!0)}_teardownObservers(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null),this._loadHandler&&(this.removeEventListener("load",this._loadHandler,!0),this._loadHandler=null)}_clearRevealTimeout(){this._revealTimeout!==null&&(clearTimeout(this._revealTimeout),this._revealTimeout=null)}_renderBlocks(){return this._blocks.map((e,s)=>{let i=e.borderRadius||`${this.fallbackRadius}px`,o=this.stagger,n=o>0?`animation-delay: ${s*o}s;`:"";return j`
123
137
  <div
124
138
  class="shimmer-block"
125
139
  style="
@@ -127,12 +141,12 @@
127
141
  top: ${e.y}px;
128
142
  width: ${e.width}px;
129
143
  height: ${e.height}px;
130
- border-radius: ${r};
144
+ border-radius: ${i};
131
145
  background: var(--shimmer-bg, ${this.backgroundColor});
132
146
  ${n}
133
147
  "
134
148
  ></div>
135
- `})}};p.styles=Ot,m([f({type:Boolean,reflect:!0})],p.prototype,"loading",2),m([f({attribute:"shimmer-color"})],p.prototype,"shimmerColor",2),m([f({attribute:"background-color"})],p.prototype,"backgroundColor",2),m([f({type:Number})],p.prototype,"duration",2),m([f({type:Number,attribute:"fallback-radius"})],p.prototype,"fallbackRadius",2),m([f({reflect:!0})],p.prototype,"animation",2),m([f({type:Number})],p.prototype,"stagger",2),m([f({type:Number})],p.prototype,"reveal",2),m([rt()],p.prototype,"_blocks",2),m([rt()],p.prototype,"_revealing",2),p=m([bt("phantom-ui")],p);})();
149
+ `})}};p.styles=Tt,m([f({type:Boolean,reflect:!0})],p.prototype,"loading",2),m([f({attribute:"shimmer-color"})],p.prototype,"shimmerColor",2),m([f({attribute:"background-color"})],p.prototype,"backgroundColor",2),m([f({type:Number})],p.prototype,"duration",2),m([f({type:Number,attribute:"fallback-radius"})],p.prototype,"fallbackRadius",2),m([f({reflect:!0})],p.prototype,"animation",2),m([f({type:Number})],p.prototype,"stagger",2),m([f({type:Number})],p.prototype,"reveal",2),m([f({type:Number,converter:e=>Math.max(1,Math.round(Number(e)||1))})],p.prototype,"count",2),m([f({type:Number,attribute:"count-gap",converter:e=>Math.max(0,Number(e)||0)})],p.prototype,"countGap",2),m([it()],p.prototype,"_blocks",2),m([it()],p.prototype,"_revealing",2),p=m([bt("phantom-ui")],p);})();
136
150
  /*! Bundled license information:
137
151
 
138
152
  @lit/reactive-element/css-tag.js:
@@ -1,34 +1,6 @@
1
1
  import { LitElement } from "lit";
2
2
  import type { CSSResult } from "lit";
3
3
  type Animation = "shimmer" | "pulse" | "breathe" | "solid";
4
- /**
5
- * `<phantom-ui>` -- A structure-aware shimmer skeleton loader.
6
- *
7
- * Wraps real content and, when `loading` is true, measures the DOM structure
8
- * of the slotted children to generate perfectly-aligned shimmer overlay blocks.
9
- *
10
- * @slot - The real content to show (or measure for skeleton generation)
11
- *
12
- * @attr {boolean} loading - Show the shimmer overlay or real content
13
- * @attr {string} shimmer-color - Color of the animated gradient wave
14
- * @attr {string} background-color - Background color of each shimmer block
15
- * @attr {number} duration - Animation cycle duration in seconds
16
- * @attr {number} fallback-radius - Border radius (px) for elements with no radius
17
- * @attr {Animation} animation - Animation mode: shimmer, pulse, breathe, or solid
18
- * @attr {number} stagger - Delay in seconds between each block's animation start
19
- * @attr {number} reveal - Fade-out duration in seconds when loading ends (0 = instant)
20
- *
21
- * @example
22
- * ```html
23
- * <phantom-ui loading animation="pulse" stagger="0.05">
24
- * <div class="card">
25
- * <img src="avatar.png" width="48" height="48" />
26
- * <h3>User Name</h3>
27
- * <p>Some description text here</p>
28
- * </div>
29
- * </phantom-ui>
30
- * ```
31
- */
32
4
  export declare class PhantomUi extends LitElement {
33
5
  static styles: CSSResult;
34
6
  /** Whether to show the shimmer overlay or the real content */
@@ -47,13 +19,20 @@ export declare class PhantomUi extends LitElement {
47
19
  stagger: number;
48
20
  /** Fade-out duration in seconds when loading ends (0 = instant) */
49
21
  reveal: number;
22
+ /** Number of skeleton rows to generate from a single template element */
23
+ count: number;
24
+ /** Gap in pixels between each repeated skeleton row (only used when count > 1) */
25
+ countGap: number;
50
26
  private _blocks;
51
27
  private _revealing;
52
28
  private _resizeObserver;
53
29
  private _mutationObserver;
30
+ private _loadHandler;
54
31
  private _measureScheduled;
55
32
  private _revealTimeout;
33
+ connectedCallback(): void;
56
34
  disconnectedCallback(): void;
35
+ willUpdate(changedProperties: Map<PropertyKey, unknown>): void;
57
36
  updated(changedProperties: Map<PropertyKey, unknown>): void;
58
37
  render(): import("lit-html").TemplateResult<1>;
59
38
  private _scheduleMeasure;
@@ -72,6 +51,8 @@ export interface PhantomUiAttributes {
72
51
  animation?: "shimmer" | "pulse" | "breathe" | "solid";
73
52
  stagger?: number;
74
53
  reveal?: number;
54
+ count?: number;
55
+ "count-gap"?: number;
75
56
  children?: unknown;
76
57
  class?: string;
77
58
  id?: string;
@@ -1,7 +1,8 @@
1
- var y=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var a=(n,i,e,s)=>{for(var t=s>1?void 0:s?_(i,e):i,r=n.length-1,l;r>=0;r--)(l=n[r])&&(t=(s?l(i,e,t):l(t))||t);return s&&t&&y(i,e,t),t};import{LitElement as T,html as c}from"lit";import{customElement as x,property as m,state as f}from"lit/decorators.js";import{styleMap as S}from"lit/directives/style-map.js";var k=new Set(["IMG","SVG","VIDEO","CANVAS","IFRAME","INPUT","TEXTAREA","BUTTON","HR"]),w=new Set(["BR","WBR","HR"]);function O(n){if(k.has(n.tagName))return!0;for(let i of n.children)if(!w.has(i.tagName))return!1;return!0}function R(n){for(let i of n.childNodes)if(i.nodeType===Node.TEXT_NODE&&i.textContent?.trim())return!0;return!1}function b(n,i){let e=[];function s(t){let r=t.getBoundingClientRect();if(r.width===0||r.height===0||t.hasAttribute("data-shimmer-ignore"))return;if(t.hasAttribute("data-shimmer-no-children")||O(t)){let d=getComputedStyle(t).borderRadius;if((t.tagName==="TD"||t.tagName==="TH")&&R(t)){let u=document.createElement("span");u.style.visibility="hidden",u.style.position="absolute",u.textContent=t.textContent,t.appendChild(u);let g=u.getBoundingClientRect();t.removeChild(u),e.push({x:r.left-i.left,y:r.top-i.top,width:Math.min(g.width,r.width),height:r.height,tag:t.tagName.toLowerCase(),borderRadius:d==="0px"?"":d});return}e.push({x:r.left-i.left,y:r.top-i.top,width:r.width,height:r.height,tag:t.tagName.toLowerCase(),borderRadius:d==="0px"?"":d});return}for(let h of t.children)s(h)}return s(n),e}function p(n,i){let e=null,s=new ResizeObserver(()=>{e!==null&&cancelAnimationFrame(e),e=requestAnimationFrame(()=>{e=null,i()})});return s.observe(n),s}import{css as E}from"lit";var v=E`
1
+ var _=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var a=(n,r,e,s)=>{for(var t=s>1?void 0:s?k(r,e):r,i=n.length-1,l;i>=0;i--)(l=n[i])&&(t=(s?l(r,e,t):l(t))||t);return s&&t&&_(r,e,t),t};import{LitElement as T,html as p}from"lit";import{customElement as C,property as m,state as f}from"lit/decorators.js";import{styleMap as S}from"lit/directives/style-map.js";var w=new Set(["IMG","SVG","VIDEO","CANVAS","IFRAME","INPUT","TEXTAREA","BUTTON","HR"]),E=new Set(["BR","WBR","HR"]);function x(n){if(w.has(n.tagName))return!0;for(let r of n.children)if(!E.has(r.tagName))return!1;return!0}function O(n){for(let r of n.childNodes)if(r.nodeType===Node.TEXT_NODE&&r.textContent?.trim())return!0;return!1}function b(n,r){let e=[];function s(t){let i=t.getBoundingClientRect();if(i.width===0||i.height===0||t.hasAttribute("data-shimmer-ignore"))return;if(t.hasAttribute("data-shimmer-no-children")||x(t)){let d=getComputedStyle(t).borderRadius;if((t.tagName==="TD"||t.tagName==="TH")&&O(t)){let u=document.createElement("span");u.style.visibility="hidden",u.style.position="absolute",u.textContent=t.textContent,t.appendChild(u);let c=u.getBoundingClientRect();t.removeChild(u),e.push({x:i.left-r.left,y:i.top-r.top,width:Math.min(c.width,i.width),height:i.height,tag:t.tagName.toLowerCase(),borderRadius:d==="0px"?"":d});return}e.push({x:i.left-r.left,y:i.top-r.top,width:i.width,height:i.height,tag:t.tagName.toLowerCase(),borderRadius:d==="0px"?"":d});return}for(let h of t.children)s(h)}return s(n),e}function v(n,r){let e=null,s=new ResizeObserver(()=>{e!==null&&cancelAnimationFrame(e),e=requestAnimationFrame(()=>{e=null,r()})});return s.observe(n),s}import{css as R}from"lit";var g=R`
2
2
  :host {
3
3
  display: block;
4
4
  position: relative;
5
+ overflow: hidden;
5
6
  --shimmer-color: rgba(255, 255, 255, 0.3);
6
7
  --shimmer-duration: 1.5s;
7
8
  --shimmer-bg: rgba(255, 255, 255, 0.08);
@@ -106,9 +107,22 @@ var y=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var a=(n,i,e,s
106
107
  :host([animation="solid"]) .shimmer-block::after {
107
108
  display: none;
108
109
  }
109
- `;var o=class extends T{constructor(){super(...arguments);this.loading=!1;this.shimmerColor="rgba(255, 255, 255, 0.3)";this.backgroundColor="rgba(255, 255, 255, 0.08)";this.duration=1.5;this.fallbackRadius=4;this.animation="shimmer";this.stagger=0;this.reveal=0;this._blocks=[];this._revealing=!1;this._resizeObserver=null;this._mutationObserver=null;this._measureScheduled=!1;this._revealTimeout=null}disconnectedCallback(){super.disconnectedCallback(),this._teardownObservers(),this._clearRevealTimeout()}updated(e){e.has("loading")&&(this.setAttribute("aria-busy",String(this.loading)),this.loading?(this._revealing=!1,this._clearRevealTimeout(),this._scheduleMeasure(),this._setupObservers()):this.reveal>0&&this._blocks.length>0?(this._revealing=!0,this._teardownObservers(),this._revealTimeout=setTimeout(()=>{this._revealing=!1,this._blocks=[],this._revealTimeout=null},this.reveal*1e3)):(this._blocks=[],this._teardownObservers()))}render(){let e=S({"--shimmer-color":this.shimmerColor,"--shimmer-duration":`${this.duration}s`,"--shimmer-bg":this.backgroundColor,"--reveal-duration":`${this.reveal}s`}),s=this.loading||this._revealing;return c`
110
+ `;var y="phantom-ui-loading-styles";function A(){if(document.getElementById(y))return;let n=document.createElement("style");n.id=y,n.textContent=`
111
+ phantom-ui[loading] * {
112
+ color: transparent !important;
113
+ -webkit-text-fill-color: transparent !important;
114
+ pointer-events: none;
115
+ user-select: none;
116
+ }
117
+ phantom-ui[loading] img,
118
+ phantom-ui[loading] svg,
119
+ phantom-ui[loading] video,
120
+ phantom-ui[loading] canvas {
121
+ opacity: 0 !important;
122
+ }
123
+ `,document.head.appendChild(n)}var o=class extends T{constructor(){super(...arguments);this.loading=!1;this.shimmerColor="rgba(255, 255, 255, 0.3)";this.backgroundColor="rgba(255, 255, 255, 0.08)";this.duration=1.5;this.fallbackRadius=4;this.animation="shimmer";this.stagger=0;this.reveal=0;this.count=1;this.countGap=0;this._blocks=[];this._revealing=!1;this._resizeObserver=null;this._mutationObserver=null;this._loadHandler=null;this._measureScheduled=!1;this._revealTimeout=null}connectedCallback(){super.connectedCallback(),A()}disconnectedCallback(){super.disconnectedCallback(),this._teardownObservers(),this._clearRevealTimeout()}willUpdate(e){e.has("loading")&&!this.loading&&this.reveal>0&&this._blocks.length>0&&(this._revealing=!0)}updated(e){(e.has("count")||e.has("countGap"))&&this.loading&&this._scheduleMeasure(),e.has("loading")&&(this.setAttribute("aria-busy",String(this.loading)),this.loading?(this._revealing=!1,this._clearRevealTimeout(),this._scheduleMeasure(),this._setupObservers()):this._revealing?(this._teardownObservers(),this._revealTimeout=setTimeout(()=>{this._revealing=!1,this._blocks=[],this._revealTimeout=null,this.style.minHeight=""},this.reveal*1e3)):(this._blocks=[],this._teardownObservers(),this.style.minHeight=""))}render(){let e=S({"--shimmer-color":this.shimmerColor,"--shimmer-duration":`${this.duration}s`,"--shimmer-bg":this.backgroundColor,"--reveal-duration":`${this.reveal}s`}),s=this.loading||this._revealing;return p`
110
124
  <slot></slot>
111
- ${s?c`
125
+ ${s?p`
112
126
  <div
113
127
  class="shimmer-overlay ${this._revealing?"revealing":""}"
114
128
  style=${e}
@@ -117,7 +131,7 @@ var y=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var a=(n,i,e,s
117
131
  ${this._renderBlocks()}
118
132
  </div>
119
133
  `:""}
120
- `}_scheduleMeasure(){this._measureScheduled||(this._measureScheduled=!0,requestAnimationFrame(()=>{this._measureScheduled=!1,this._measure()}))}_measure(){if(!this.loading)return;let e=this.getBoundingClientRect();if(e.width===0||e.height===0)return;let s=this.shadowRoot?.querySelector("slot");if(!s)return;let t=s.assignedElements({flatten:!0}),r=[];for(let l of t){let h=b(l,e);r.push(...h)}this._blocks=r}_setupObservers(){this._teardownObservers(),this._resizeObserver=p(this,()=>{this._scheduleMeasure()}),this._mutationObserver=new MutationObserver(()=>{this._scheduleMeasure()}),this._mutationObserver.observe(this,{childList:!0,subtree:!0,attributes:!0})}_teardownObservers(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null)}_clearRevealTimeout(){this._revealTimeout!==null&&(clearTimeout(this._revealTimeout),this._revealTimeout=null)}_renderBlocks(){return this._blocks.map((e,s)=>{let t=e.borderRadius||`${this.fallbackRadius}px`,r=this.stagger,l=r>0?`animation-delay: ${s*r}s;`:"";return c`
134
+ `}_scheduleMeasure(){this._measureScheduled||(this._measureScheduled=!0,requestAnimationFrame(()=>{this._measureScheduled=!1,this._measure()}))}_measure(){if(!this.loading)return;let e=this.getBoundingClientRect();if(e.width===0||e.height===0)return;let s=this.shadowRoot?.querySelector("slot");if(!s)return;let t=s.assignedElements({flatten:!0}),i=[];for(let l of t){let h=b(l,e);i.push(...h)}if(this.count>1&&i.length>0){let l=0;for(let u of t){let c=u.getBoundingClientRect();l=Math.max(l,c.bottom-e.top)}let h=[...i];for(let u=1;u<this.count;u++)for(let c of h)i.push({...c,y:c.y+u*(l+this.countGap)});let d=this.count*l+(this.count-1)*this.countGap;this.style.minHeight=`${d}px`}else this.style.minHeight="";this._blocks=i}_setupObservers(){this._teardownObservers(),this._resizeObserver=v(this,()=>{this._scheduleMeasure()}),this._mutationObserver=new MutationObserver(()=>{this._scheduleMeasure()}),this._mutationObserver.observe(this,{childList:!0,subtree:!0,attributes:!0}),this._loadHandler=()=>this._scheduleMeasure(),this.addEventListener("load",this._loadHandler,!0)}_teardownObservers(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null),this._loadHandler&&(this.removeEventListener("load",this._loadHandler,!0),this._loadHandler=null)}_clearRevealTimeout(){this._revealTimeout!==null&&(clearTimeout(this._revealTimeout),this._revealTimeout=null)}_renderBlocks(){return this._blocks.map((e,s)=>{let t=e.borderRadius||`${this.fallbackRadius}px`,i=this.stagger,l=i>0?`animation-delay: ${s*i}s;`:"";return p`
121
135
  <div
122
136
  class="shimmer-block"
123
137
  style="
@@ -130,4 +144,4 @@ var y=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var a=(n,i,e,s
130
144
  ${l}
131
145
  "
132
146
  ></div>
133
- `})}};o.styles=v,a([m({type:Boolean,reflect:!0})],o.prototype,"loading",2),a([m({attribute:"shimmer-color"})],o.prototype,"shimmerColor",2),a([m({attribute:"background-color"})],o.prototype,"backgroundColor",2),a([m({type:Number})],o.prototype,"duration",2),a([m({type:Number,attribute:"fallback-radius"})],o.prototype,"fallbackRadius",2),a([m({reflect:!0})],o.prototype,"animation",2),a([m({type:Number})],o.prototype,"stagger",2),a([m({type:Number})],o.prototype,"reveal",2),a([f()],o.prototype,"_blocks",2),a([f()],o.prototype,"_revealing",2),o=a([x("phantom-ui")],o);export{o as PhantomUi};
147
+ `})}};o.styles=g,a([m({type:Boolean,reflect:!0})],o.prototype,"loading",2),a([m({attribute:"shimmer-color"})],o.prototype,"shimmerColor",2),a([m({attribute:"background-color"})],o.prototype,"backgroundColor",2),a([m({type:Number})],o.prototype,"duration",2),a([m({type:Number,attribute:"fallback-radius"})],o.prototype,"fallbackRadius",2),a([m({reflect:!0})],o.prototype,"animation",2),a([m({type:Number})],o.prototype,"stagger",2),a([m({type:Number})],o.prototype,"reveal",2),a([m({type:Number,converter:e=>Math.max(1,Math.round(Number(e)||1))})],o.prototype,"count",2),a([m({type:Number,attribute:"count-gap",converter:e=>Math.max(0,Number(e)||0)})],o.prototype,"countGap",2),a([f()],o.prototype,"_blocks",2),a([f()],o.prototype,"_revealing",2),o=a([C("phantom-ui")],o);export{o as PhantomUi};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aejkatappaja/phantom-ui",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Structure-aware shimmer skeleton loader as a universal Web Component built with Lit. Works with React, Vue, Svelte, Angular, Solid, or vanilla JS.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,11 @@
38
38
  "format": "biome format --write .",
39
39
  "storybook": "storybook dev -p 6006",
40
40
  "build-storybook": "storybook build",
41
- "prepare": "husky"
41
+ "prepare": "husky",
42
+ "test": "web-test-runner",
43
+ "test:watch": "web-test-runner --watch",
44
+ "test:all": "web-test-runner --all-browsers",
45
+ "playground": "bunx --bun serve -l 4444 --no-clipboard"
42
46
  },
43
47
  "keywords": [
44
48
  "skeleton",
@@ -57,9 +61,13 @@
57
61
  "devDependencies": {
58
62
  "@biomejs/biome": "^1.9.0",
59
63
  "@custom-elements-manifest/analyzer": "^0.11.0",
64
+ "@open-wc/testing": "^4.0.0",
60
65
  "@storybook/addon-essentials": "^8.4.0",
61
66
  "@storybook/web-components": "^8.4.0",
62
67
  "@storybook/web-components-vite": "^8.4.0",
68
+ "@web/dev-server-esbuild": "^1.0.5",
69
+ "@web/test-runner": "^0.20.2",
70
+ "@web/test-runner-playwright": "^0.11.1",
63
71
  "husky": "^9.1.7",
64
72
  "lint-staged": "^16.4.0",
65
73
  "storybook": "^8.4.0",