shimmer-trace 1.1.3 → 1.2.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/AGENTS.md CHANGED
@@ -8,7 +8,9 @@
8
8
 
9
9
  ## What This Library Does (One Paragraph)
10
10
 
11
- `shimmer-trace` is a React skeleton loading library. It renders your real component invisibly, walks the live DOM to find every visible leaf element (headings, paragraphs, images, inputs, buttons, etc.), measures each one's exact position and size via `getBoundingClientRect()`, then paints an absolutely-positioned shimmer overlay on top of those measured rects. The skeleton is therefore pixel-perfect and auto-updates via `ResizeObserver`. You never write a manual skeleton. You wrap your component and pass `loading={true}`.
11
+ `shimmer-trace` is a React skeleton loading library. It renders your real component, walks the live DOM to find every visible leaf element (headings, paragraphs, images, inputs, buttons, etc.), measures each one's exact position and size via `getBoundingClientRect()`, then paints an absolutely-positioned shimmer overlay on top of those measured rects. The skeleton is therefore pixel-perfect and auto-updates via `ResizeObserver`. You never write a manual skeleton. You wrap your component and pass `loading={true}`.
12
+
13
+ The library is **client-only** by nature — measurement requires a real DOM — but its bundled output is marked with `'use client'`, so it can be **imported directly from React Server Components / Next.js App Router pages** without manual wrapping.
12
14
 
13
15
  ---
14
16
 
@@ -20,19 +22,29 @@ npm install shimmer-trace
20
22
 
21
23
  **Peer deps required:** `react >= 18.0.0`, `react-dom >= 18.0.0`
22
24
 
25
+ ### Server vs Client Components (Next.js App Router)
26
+
27
+ - The package's bundled `dist/index.mjs` and `dist/index.js` both start with `'use client';`. Every exported component (`Shimmer`, `ShimmerSuspense`, `createShimmer`) and hook (`useIsShimmering`, `useShimmerContext`) crosses the client boundary automatically.
28
+ - **You can import the package from a Server Component file.** Next.js will treat the imported subgraph as client code. You do NOT need to add `'use client'` at the top of a page just because it imports `Shimmer`.
29
+ - **Children passed to `<Shimmer>` follow normal RSC rules.** A Server Component child that produces DOM synchronously will render and be measured fine. A Server Component child that suspends needs `<ShimmerSuspense>` instead — otherwise it produces no DOM during the fallback and the skeleton is empty.
30
+ - All measurement uses `window`, `document`, `getBoundingClientRect`, and `ResizeObserver`. There is no SSR measurement pass; the skeleton paints after hydration.
31
+
23
32
  ---
24
33
 
25
34
  ## Public API — Full Export List
26
35
 
27
36
  ```ts
28
37
  // Components
29
- import { Shimmer } from 'shimmer-trace'; // main component
30
- import { ShimmerSuspense } from 'shimmer-trace'; // Suspense boundary with auto-skeleton
31
- import { createShimmer } from 'shimmer-trace'; // factory — bakes config into component
38
+ import { Shimmer } from 'shimmer-trace'; // main component
39
+ import { ShimmerSuspense } from 'shimmer-trace'; // Suspense boundary with auto-skeleton
40
+ import { createShimmer } from 'shimmer-trace'; // factory — bakes config into component
32
41
 
33
42
  // Hooks
34
- import { useIsShimmering } from 'shimmer-trace'; // true when inside ShimmerSuspense fallback
35
- import { useShimmerContext } from 'shimmer-trace'; // raw context — advanced use only
43
+ import { useIsShimmering } from 'shimmer-trace'; // true when inside ShimmerSuspense fallback
44
+ import { useShimmerContext } from 'shimmer-trace'; // raw context value — advanced use only
45
+
46
+ // Raw context (rarely needed — only if you build a custom Master/Reporter outside <Shimmer>)
47
+ import { ShimmerContext } from 'shimmer-trace';
36
48
 
37
49
  // Types
38
50
  import type {
@@ -285,7 +297,7 @@ Use when: multiple sub-sections exist but you want one synchronized shimmer acro
285
297
  </Shimmer>
286
298
  ```
287
299
 
288
- **Key rule:** inner `<Shimmer>` without `loading` prop inside an outer `<Shimmer>` auto-becomes a Reporter. It measures its own subtree and sends rects to the Master. One overlay covers everything.
300
+ **Key rule:** Any nested `<Shimmer>` inside an outer `<Shimmer>` auto-becomes a Reporter, regardless of whether it has its own `loading` prop. The Reporter measures its own subtree, sends rects to the Master, and ignores its own `loading` prop — Master's `loading` controls everything. One overlay covers all. To break out and create an independent Master, use `stopPropagation={true}` (see Pattern 8).
289
301
 
290
302
  ---
291
303
 
@@ -323,26 +335,29 @@ Use when: component uses `use()`, `useSuspenseQuery`, or similar — throws a Pr
323
335
 
324
336
  ### Option A — `template` prop (component has zero shimmer awareness)
325
337
 
338
+ Reuse the same component as its own template — pass template props so it renders DOM without suspending. No duplicate skeleton component, no `&nbsp;` width padding.
339
+
326
340
  ```tsx
327
341
  import { ShimmerSuspense } from 'shimmer-trace';
328
342
 
329
- // Skeleton template: same structure, no real data
330
- const UserCardTemplate = () => (
331
- <div className="profile-card">
332
- <img className="avatar" src="" alt="" />
333
- <div className="info">
334
- <h3>&nbsp;</h3>
335
- <span>&nbsp;</span>
336
- <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
337
- </div>
338
- </div>
339
- );
343
+ // Template data: same shape the real component expects, no fetch
344
+ const userTemplate = {
345
+ name: 'xxxxxxxxxxxxxx',
346
+ role: 'xxxxxxxxxx',
347
+ bio: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
348
+ avatar: '',
349
+ };
340
350
 
341
- <ShimmerSuspense template={<UserCardTemplate />} animation="wave">
351
+ <ShimmerSuspense template={<UserCard user={userTemplate} />} animation="wave">
342
352
  <UserCard /> {/* throws Promise while fetching — shimmer shows automatically */}
343
353
  </ShimmerSuspense>
344
354
  ```
345
355
 
356
+ **Why a `template` prop at all (not just `dummyData` like `<Shimmer>`):** the real `<UserCard />` throws a Promise during render — it never produces DOM until data resolves. `cloneElement` + props merge doesn't help because the cloned element still suspends. `template` renders a separate, non-suspending instance (same component, template data) so Shimmer gets real DOM to trace.
357
+
358
+ **Rule:** template should render synchronously. If you pass `<UserCard resource={realResource} />` as template, it'll suspend inside the fallback and skeleton goes empty. Either pass template data props (above) or use Option B.
359
+
360
+
346
361
  ### Option B — `useIsShimmering` hook (component skips fetch in shimmer mode)
347
362
 
348
363
  ```tsx
@@ -405,8 +420,25 @@ Use when: nested Shimmer should NOT bubble rects to parent — it manages its ow
405
420
  <span data-shimmer-ignore>
406
421
  <DecorativeIcon />
407
422
  </span>
423
+
424
+ // Force trace a position:fixed / position:sticky element (overrides
425
+ // the auto-skip described in "Known Limitations"). The block will
426
+ // drift on scroll — only use this on non-scrolling pages or when the
427
+ // fixed element is short-lived.
428
+ <div data-shimmer style={{ position: 'fixed', top: 0 }}>
429
+ <Banner />
430
+ </div>
408
431
  ```
409
432
 
433
+ **Precedence** (matches source order in `useTrace.ts`):
434
+
435
+ 1. `data-shimmer-ignore` → never traced, subtree skipped.
436
+ 2. `data-shimmer-reporter` → internal, skipped by walk.
437
+ 3. `data-shimmer` on a `position: fixed` / `sticky` element → trace it anyway (override).
438
+ 4. No override + `fixed` / `sticky` position → skip subtree, warn once per Master.
439
+ 5. `data-shimmer` on a normal element → force-trace.
440
+ 6. Default: tag-whitelist or visible-leaf heuristic.
441
+
410
442
  ---
411
443
 
412
444
  ## Config Inheritance Chain
@@ -563,6 +595,33 @@ function UserCard() {
563
595
 
564
596
  Library injects one `<style>` tag with id `shimmer-trace-styles` into `document.head` on first render. Contains only `@keyframes` definitions and `preserveBackground` CSS attribute selectors. Safe to SSR — guard is `typeof document === 'undefined'`.
565
597
 
598
+ Injection runs inside `useInsertionEffect`, not `useEffect`. This means the keyframes are present in the document **before the first paint** of any `<Shimmer>` subtree, so there is no first-frame FOUC (no momentary static gray blocks before the wave starts). Agents should not "fix" this back to `useEffect` — the timing is intentional.
599
+
600
+ ## Clone Keys & Hydration
601
+
602
+ When `dummyLength` or `dummyData` causes Shimmer to clone children, each clone receives a key of the form `${parentShimmerId}-${slot}-${index}`, where `parentShimmerId` comes from React's `useId()` (stable across SSR and hydration).
603
+
604
+ Keys are deterministic per render slot. Agents should:
605
+
606
+ - **Not** assume keys change between renders.
607
+ - **Not** introduce a module-scope counter into `utils.ts` or anywhere else — the previous implementation did this and it caused (a) hydration mismatch warnings when SSR and client incremented the counter differently and (b) full remount of every cloned child on every parent re-render.
608
+ - Rely on `useId()` already being called inside `<Shimmer>` for any new keying logic.
609
+
610
+ ---
611
+
612
+ ## Known Limitations (Agents: do not invent fixes that aren't in source)
613
+
614
+ These are real gaps in the current implementation. If a user asks why their setup misbehaves, match the symptom to one of these before debugging deeper.
615
+
616
+ - **Portals are silently skipped.** `collectTraceableElements` walks the descendants of the Master container ref. Anything mounted via `ReactDOM.createPortal` lives elsewhere in the DOM and never enters the walk. No console warning. Workaround: put a separate `<Shimmer>` *inside* the portal target.
617
+ - **`position: fixed` / `position: sticky` children are detected and skipped.** The rect math is `el.getBoundingClientRect() - container.getBoundingClientRect()`. For fixed/sticky elements that coordinate space diverges from the container as soon as the page scrolls, so any overlay block we generated would drift. `collectTraceableElements` calls `getComputedStyle(el).position` during the walk; if it's `fixed` or `sticky`, the entire subtree is skipped and one `console.warn` is emitted per Master container (deduped via a `WeakSet`, so resize-driven re-traces never re-warn). The warning fires in production too — it's intentional. Two opt-ins exist:
618
+ - Add `data-shimmer` to the fixed element to force-trace it (user accepts the scroll drift). When `data-shimmer` is present, the position check is bypassed.
619
+ - Recommended: render a separate `<Shimmer>` *inside* the fixed element. Master/Reporter detection handles the nesting, and the inner overlay sits inside the fixed coordinate space, so alignment works.
620
+ - **Transformed ancestors.** The overlay sits inside the Master container, so it inherits the same transform stack — this usually renders correctly. A transform applied *between* the Master container and a traced descendant can desynchronize the overlay block from its source element.
621
+ - **Suspending Server Components inside plain `<Shimmer>`.** Without `<ShimmerSuspense>`, a suspending child produces no DOM during the fallback, so the trace returns zero rects and the skeleton is empty. Always recommend `ShimmerSuspense` for suspending children.
622
+ - **Server-side measurement is not supported.** There is no DOM on the server. The first paint after hydration is when measurements happen. Agents should not promise SSR-rendered skeletons — only that hydration is clean.
623
+ - **`getBoundingClientRect` is called twice per leaf** (once in `isTraceable` for the dimension check, once in `measureElement`). This is a known perf bottleneck on very large trees and is on the roadmap; do not claim it's already optimized.
624
+
566
625
  ---
567
626
 
568
627
  ## TypeScript Usage
package/README.md CHANGED
@@ -43,9 +43,14 @@ It renders your real component invisibly, traces every element's exact position
43
43
 
44
44
  - **Auto-tracing** — Measures real DOM layout. No manual skeleton code.
45
45
  - **Zero CLS** — Container layout preserved. Default `preserveBackground` keeps card backgrounds, borders, and padding visible underneath the shimmer.
46
+ - **Next.js App Router / RSC ready** — Ships with `'use client'` directive baked into the bundled output. Import directly from a Server Component without a wrapper.
47
+ - **SSR-safe** — Deterministic clone keys across server and client. No hydration mismatch warnings, no remount of cloned children on every render.
48
+ - **No first-frame FOUC** — Animation styles are injected via `useInsertionEffect` so keyframes land before the first paint.
46
49
  - **Synchronized animation** — One overlay, one wave. All skeletons animate in perfect sync.
47
50
  - **5 animation styles** — `wave`, `pulse`, `shine`, `glow`, `gradient`.
48
- - **List mode** — `dummyLength` clones your list items for skeleton lists, with template caching.
51
+ - **Dummy data injection** — `dummyData` clones children with template props so skeletons render with realistic shape, no `data || fallback` ternaries in JSX.
52
+ - **List mode** — `dummyLength` clones the first child N times for skeleton lists, even when your array is empty.
53
+ - **Component templates** — `as={MovieCard}` generates skeletons from a component + `dummyData`, no children required.
49
54
  - **Suspense-native** — `ShimmerSuspense` wraps any suspended component with no `loading` prop.
50
55
  - **Factory pattern** — `createShimmer` pre-bakes your config. Use it like a component everywhere.
51
56
  - **Composable** — Nested `Shimmer` components bubble their rects up to a single master overlay.
@@ -69,6 +74,31 @@ pnpm add shimmer-trace
69
74
 
70
75
  ---
71
76
 
77
+ ## Next.js App Router (RSC) usage
78
+
79
+ `shimmer-trace` ships its bundled output with a top-of-file `'use client'` directive, so you can import `Shimmer` (or `ShimmerSuspense`, `createShimmer`) directly from a Server Component without crashing the build.
80
+
81
+ ```tsx
82
+ // app/profile/page.tsx — Server Component, no 'use client' at the top
83
+ import { Shimmer } from "shimmer-trace";
84
+
85
+ export default function ProfilePage() {
86
+ return (
87
+ <Shimmer loading>
88
+ <UserCard />
89
+ </Shimmer>
90
+ );
91
+ }
92
+ ```
93
+
94
+ Notes:
95
+
96
+ - The `<Shimmer>` boundary itself is a Client Component. Children you pass through it must also be renderable as Client Components if they use state, effects, or browser APIs.
97
+ - The library uses `getBoundingClientRect`, `ResizeObserver`, and `useInsertionEffect`, all of which only run in the browser. There is no server-side measurement step — the skeleton appears after hydration.
98
+ - Server Component children that suspend should be wrapped with `ShimmerSuspense` (see [Suspense](#shimmersuspense--suspense-native-loading) below).
99
+
100
+ ---
101
+
72
102
  ## Quick Start
73
103
 
74
104
  ```tsx
@@ -87,6 +117,19 @@ function ProfilePage() {
87
117
 
88
118
  That's it. `shimmer-trace` walks the DOM inside `<UserCard />`, finds every text node, image, input, and button, and draws a shimmer skeleton that matches it exactly.
89
119
 
120
+ Need realistic shape before real data arrives? Pass a template via `dummyData`:
121
+
122
+ ```tsx
123
+ <Shimmer
124
+ loading={loading}
125
+ dummyData={{ user: { name: "dummy_user", role: "dummy_role", avatar: "" } }}
126
+ >
127
+ <UserCard user={user} />
128
+ </Shimmer>
129
+ ```
130
+
131
+ See [Examples](#examples) for `dummyLength` (list mode) and `as` (component template) patterns.
132
+
90
133
  ---
91
134
 
92
135
  ## API Reference
@@ -103,7 +146,10 @@ The core component. Wrap anything with it.
103
146
  highlightColor="#f5f5f5" // shimmer highlight color
104
147
  speed={1.5} // animation duration in seconds
105
148
  borderRadius="4px" // override auto-detected border-radius
149
+ preserveBackground={true} // keep card bg/borders visible under shimmer
150
+ dummyData={{ user: tpl }} // inject template props into children
106
151
  dummyLength={10} // list mode: number of skeleton items
152
+ as={UserCard} // component template — generate skeletons from a component
107
153
  stopPropagation={false} // force this Shimmer to be a master
108
154
  className="my-class" // applied to the container div
109
155
  style={{ display: "flex" }} // merged into container styles
@@ -112,19 +158,21 @@ The core component. Wrap anything with it.
112
158
  </Shimmer>
113
159
  ```
114
160
 
115
- | Prop | Type | Default | Description |
116
- | -------------------- | ------------------------------------------------------ | ----------- | --------------------------------------------------- |
117
- | `loading` | `boolean` | `false` | Enables the shimmer skeleton |
118
- | `animation` | `'wave' \| 'pulse' \| 'shine' \| 'glow' \| 'gradient'` | `'wave'` | Animation style |
119
- | `preserveBackground` | `boolean` | `true` | Keep card backgrounds/borders visible while loading |
120
- | `baseColor` | `string` | `'#e0e0e0'` | Base skeleton color |
121
- | `highlightColor` | `string` | `'#f5f5f5'` | Shimmer highlight color |
122
- | `speed` | `number` | `1.5` | Animation speed in seconds |
123
- | `borderRadius` | `string` | auto | Override border-radius on all blocks |
124
- | `dummyLength` | `number` | — | Enables list mode (see below) |
125
- | `stopPropagation` | `boolean` | `false` | Force master renderer, ignore parent context |
126
- | `className` | `string` | — | Class on the container `<div>` |
127
- | `style` | `CSSProperties` | | Inline styles on the container `<div>` |
161
+ | Prop | Type | Default | Description |
162
+ | -------------------- | ------------------------------------------------------ | ----------- | ------------------------------------------------------------------------ |
163
+ | `loading` | `boolean` | `false` | Enables the shimmer skeleton |
164
+ | `animation` | `'wave' \| 'pulse' \| 'shine' \| 'glow' \| 'gradient'` | `'wave'` | Animation style |
165
+ | `preserveBackground` | `boolean` | `true` | Keep card backgrounds/borders visible while loading |
166
+ | `baseColor` | `string` | `'#e0e0e0'` | Base skeleton color |
167
+ | `highlightColor` | `string` | `'#f5f5f5'` | Shimmer highlight color |
168
+ | `speed` | `number` | `1.5` | Animation speed in seconds |
169
+ | `borderRadius` | `string` | auto | Override border-radius on all blocks |
170
+ | `dummyData` | `Record<string, any>` | — | Props merged into each child while loading (template data, no real API) |
171
+ | `dummyLength` | `number` | | List mode clones first child N times (see below) |
172
+ | `as` | `ComponentType<any>` | — | Component template renders `dummyLength` × `<as {...dummyData} />` |
173
+ | `stopPropagation` | `boolean` | `false` | Force master renderer, ignore parent context |
174
+ | `className` | `string` | — | Class on the container `<div>` |
175
+ | `style` | `CSSProperties` | — | Inline styles on the container `<div>` |
128
176
 
129
177
  ---
130
178
 
@@ -173,32 +221,74 @@ Works out of the box with inputs, labels, and buttons.
173
221
  </Shimmer>
174
222
  ```
175
223
 
176
- ### 3. List Skeleton with `dummyLength`
224
+ ### 3. Skeleton Shape with `dummyData`
225
+
226
+ No more `data?.name ?? 'Loading...'` ternaries scattered through your component. Pass a template object via `dummyData` and Shimmer clones each child with those props merged on top of its own.
227
+
228
+ ```tsx
229
+ const userTemplate = {
230
+ name: "",
231
+ role: "",
232
+ avatar: "",
233
+ bio: "",
234
+ };
235
+
236
+ <Shimmer loading={loading} dummyData={{ user: userTemplate }}>
237
+ <UserCard user={user} />
238
+ </Shimmer>;
239
+ ```
240
+
241
+ While `loading=true`, `<UserCard>` is cloned with `user={userTemplate}` — giving the shimmer realistic shape even before any data arrives. Once `loading=false`, real props pass through untouched.
242
+
243
+ ### 4. List Skeleton with `dummyLength` + `dummyData`
177
244
 
178
- Loading a list from an API? `dummyLength` clones your list item template to show the right number of skeleton rows — even when the array is empty.
245
+ Loading a list from an API? `dummyLength` clones a template N times so the skeleton shows the right number of rows — even when your array is empty during the first fetch.
179
246
 
180
247
  ```tsx
181
- <Shimmer loading={loading} dummyLength={10}>
248
+ const postTemplate = {
249
+ title: "xxxxxxxxxxxxxxxxxxxx",
250
+ author: "xxxxxxxx",
251
+ category: "xxxxx",
252
+ thumbnail: "",
253
+ };
254
+
255
+ <Shimmer
256
+ loading={loading}
257
+ dummyLength={10}
258
+ dummyData={{ post: postTemplate }}
259
+ >
182
260
  {posts.map((post) => (
183
- <div className="post-row" key={post.id}>
184
- <img src={post.thumbnail} alt="" />
185
- <div>
186
- <h4>{post.title}</h4>
187
- <span>{post.author}</span>
188
- </div>
189
- <span className="badge">{post.category}</span>
190
- </div>
261
+ <PostRow post={post} key={post.id} />
191
262
  ))}
192
- </Shimmer>
263
+ </Shimmer>;
193
264
  ```
194
265
 
195
266
  **How it works:**
196
267
 
197
- - `loading=false` → renders your `.map()` output normally
198
- - `loading=true` → grabs the first list item, clones it `dummyLength` times, and shimmers it
199
- - If your array is empty during loading (e.g., `posts = []`), shimmer-trace uses a **cached template** from the previous render — the skeleton always matches your real layout
268
+ - `loading=false` → renders your `.map()` output normally.
269
+ - `loading=true` with children → grabs the first child, merges `dummyData` into its props, clones it `dummyLength` times.
270
+ - `loading=true` with empty array use `as` (next example) so there's a component to clone even with no children.
271
+
272
+ ### 5. Component Template with `as`
273
+
274
+ When your array is empty on first render (e.g. `posts = []` before fetch), there's no child to clone. Use `as` to point Shimmer at the component directly — it renders `dummyLength` instances of `<as {...dummyData} />`.
275
+
276
+ ```tsx
277
+ <Shimmer
278
+ loading={loading}
279
+ as={PostRow}
280
+ dummyData={{ post: postTemplate }}
281
+ dummyLength={10}
282
+ >
283
+ {posts.map((post) => (
284
+ <PostRow post={post} key={post.id} />
285
+ ))}
286
+ </Shimmer>
287
+ ```
288
+
289
+ Cold-start safe — no children needed during loading. Children render normally once `loading=false`.
200
290
 
201
- ### 4. Synchronized Flex Layout
291
+ ### 6. Synchronized Flex Layout
202
292
 
203
293
  One `<Shimmer>` wraps multiple cards. One overlay. One perfectly synchronized wave.
204
294
 
@@ -212,7 +302,7 @@ One `<Shimmer>` wraps multiple cards. One overlay. One perfectly synchronized wa
212
302
 
213
303
  No separate shimmers per card. One master overlay covers them all — the wave sweeps the entire row in sync.
214
304
 
215
- ### 5. Custom Colors (Dark Mode)
305
+ ### 7. Custom Colors (Dark Mode)
216
306
 
217
307
  ```tsx
218
308
  <Shimmer loading={loading} baseColor="#1e1e3a" highlightColor="#2d2d52">
@@ -261,7 +351,7 @@ import { ShimmerSuspense } from "shimmer-trace";
261
351
 
262
352
  ### Option A: Explicit template (recommended)
263
353
 
264
- Pass the same component without data as `template`. Zero shimmer-awareness needed in your component.
354
+ Reuse the same component as its own skeleton — pass it through `template` with template props. No duplicate skeleton component, no `&nbsp;` width hacks.
265
355
 
266
356
  ```tsx
267
357
  function UserCard({ user }) {
@@ -274,20 +364,20 @@ function UserCard({ user }) {
274
364
  );
275
365
  }
276
366
 
277
- // Same shape, no data — used as skeleton template
278
- const UserCardSkeleton = () => (
279
- <div className="card">
280
- <img src="" alt="" />
281
- <h3>&nbsp;</h3>
282
- <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
283
- </div>
284
- );
367
+ // Template data — same shape as real user, no fetch
368
+ const userTemplate = {
369
+ name: "xxxxxxxxxxxxxx",
370
+ bio: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
371
+ avatar: "",
372
+ };
285
373
 
286
- <ShimmerSuspense template={<UserCardSkeleton />}>
374
+ <ShimmerSuspense template={<UserCard user={userTemplate} />}>
287
375
  <UserCard resource={resource} />
288
376
  </ShimmerSuspense>;
289
377
  ```
290
378
 
379
+ Why a template prop at all (not just `dummyData` like `<Shimmer>`)? Because the real `<UserCard resource={resource} />` throws a Promise during render — it never produces DOM until data resolves. The library can't merge props into a component that's mid-suspend. Rendering a separate, non-suspending instance (same component, template data) gives Shimmer real DOM to trace.
380
+
291
381
  ### Option B: `useIsShimmering` hook
292
382
 
293
383
  No template needed. The component detects shimmer mode and renders an empty shape.
@@ -373,19 +463,21 @@ Fine-tune what gets traced with data attributes:
373
463
  <div data-shimmer-ignore>Never shimmer this</div>
374
464
  ```
375
465
 
466
+ `data-shimmer` is also the explicit opt-in for tracing `position: fixed` / `position: sticky` elements — the library skips those by default to avoid scroll drift. See [Known Limitations](#known-limitations) for the trade-off.
467
+
376
468
  ---
377
469
 
378
470
  ## How It Works
379
471
 
380
- 1. **Render real DOM** — `Shimmer` renders children normally. With `preserveBackground` (default), CSS rules hide text (`color: transparent`) and media (`opacity: 0`) on leaf elements while keeping container backgrounds, borders, and padding fully visible. Layout stays identicalzero CLS.
472
+ 1. **Inject keyframes pre-paint** — On first mount, the library inserts its `@keyframes` and `preserveBackground` CSS rules into `document.head` via `useInsertionEffect`. This runs before any layout effect or paint, so the wave animation is live on the very first frame no flash of unstyled (static) shimmer blocks.
381
473
 
382
- 2. **Walk the DOM** — `useTrace` recursively traverses the container, collecting every traceable element: headings, paragraphs, images, inputs, buttons, and leaf nodes with visible dimensions.
474
+ 2. **Render real DOM** — `Shimmer` renders children normally. With `preserveBackground` (default), CSS rules hide text (`color: transparent`) and media (`opacity: 0`) on leaf elements while keeping container backgrounds, borders, and padding fully visible. Layout stays identical — zero CLS.
383
475
 
384
- 3. **Measure everything** — Each element is measured with `getBoundingClientRect()` relative to the master container, capturing position, size, and computed `border-radius`.
476
+ 3. **Walk the DOM** — `useTrace` recursively traverses the container, collecting every traceable element: headings, paragraphs, images, inputs, buttons, and leaf nodes with visible dimensions.
385
477
 
386
- 4. **Build the overlay** — One absolutely-positioned `<div>` is rendered per traced rect, sized and positioned to match exactly. For sweep animations (`wave`, `shine`), each block also gets a gradient layer that spans the full container width the highlight sweeps across all blocks in perfect sync.
478
+ 4. **Measure everything** — Each element is measured with `getBoundingClientRect()` relative to the master container, capturing position, size, and computed `border-radius`.
387
479
 
388
- 5. **ResizeObserver** — Container resize triggers an automatic re-trace, so the skeleton stays pixel-perfect on responsive layouts.
480
+ 5. **Build the overlay** — One absolutely-positioned `<div>` is rendered per traced rect, sized and positioned to match exactly. For sweep animations (`wave`, `shine`), each block also gets a gradient layer that spans the full container width the highlight sweeps across all blocks in perfect sync.
389
481
 
390
482
  6. **Re-trace on resize** — `ResizeObserver` watches the container and re-measures on every resize, keeping skeletons accurate at any screen size.
391
483
 
@@ -400,24 +492,53 @@ import type {
400
492
  ShimmerProps, // Props for <Shimmer>
401
493
  ShimmerConfig, // Config options (colors, speed, animation)
402
494
  ShimmerRect, // Measured element rectangle
403
- AnimationType, // 'wave' | 'pulse' | 'breathe'
404
- ShimmerSuspenseProps,
495
+ AnimationType, // 'wave' | 'pulse' | 'shine' | 'glow' | 'gradient'
496
+ ShimmerSuspenseProps, // Props for <ShimmerSuspense>
405
497
  } from "shimmer-trace";
406
498
  ```
407
499
 
500
+ Runtime exports:
501
+
502
+ ```ts
503
+ import {
504
+ Shimmer,
505
+ createShimmer,
506
+ ShimmerSuspense,
507
+ ShimmerContext,
508
+ useShimmerContext,
509
+ useIsShimmering,
510
+ } from "shimmer-trace";
511
+ ```
512
+
513
+ ---
514
+
515
+ ## Known Limitations
516
+
517
+ These are real edge cases the library does **not** currently handle gracefully. Worth knowing before you wrap something complex.
518
+
519
+ - **React Portals are skipped silently.** `useTrace` walks the subtree of the Master container; anything rendered into a portal (e.g. `createPortal(<Modal/>, document.body)`) is mounted outside that subtree, so it never gets measured and never gets a shimmer block. Use `<Shimmer>` *inside* the portal target if you need it shimmered there.
520
+ - **`position: fixed` / `position: sticky` children are auto-skipped.** Their coordinate space cannot follow the Master container during scroll, so the overlay block would drift. The library detects them during the trace walk and silently skips the entire subtree, emitting one `console.warn` per Master container (deduped via a `WeakSet`, so resize-driven re-traces never re-warn). The warning fires in production too — it's an actionable signal, not log noise. Two workarounds:
521
+ - **Recommended:** put a nested `<Shimmer>` *inside* the fixed element. The inner Master sits in the fixed coordinate space and aligns correctly.
522
+ - **Override:** add `data-shimmer` to the fixed element to force-trace it. The block will drift on scroll — you accept the trade-off.
523
+ - **Heavily-transformed ancestors.** If an ancestor of the Master container has a CSS `transform`, the overlay sits inside the same transformed space and usually renders correctly. If a *descendant* has a transform that the rect math doesn't expect, the overlay block may not line up.
524
+ - **Suspending Server Component children.** A Server Component that suspends inside `<Shimmer>` (without `ShimmerSuspense`) won't produce DOM for the library to measure, so the skeleton appears empty. Use `ShimmerSuspense` for the suspending boundary, or pass template data via `dummyData`.
525
+
526
+ If you hit one of these in a real app, please open an issue with a reproduction.
527
+
408
528
  ---
409
529
 
410
530
  ## Comparison
411
531
 
412
- | | shimmer-trace | react-loading-skeleton | MUI Skeleton |
413
- | ---------------------- | ---------------- | ---------------------- | -------------- |
414
- | Manual skeleton code | ❌ None | ✅ Required | ✅ Required |
415
- | Matches real layout | ✅ Automatically | ⚠️ Manual | ⚠️ Manual |
416
- | List mode | ✅ `dummyLength` | ❌ | ❌ |
417
- | Suspense support | ✅ Native | ❌ | ❌ |
418
- | Synchronized animation | ✅ One overlay | ⚠️ Per-element | ⚠️ Per-element |
419
- | Zero layout shift | ✅ | ⚠️ | ⚠️ |
420
- | Bundle size | ~3kb | ~5kb | ~12kb |
532
+ | | shimmer-trace | react-loading-skeleton | MUI Skeleton |
533
+ | ---------------------- | ------------------------- | ---------------------- | -------------- |
534
+ | Manual skeleton code | ❌ None | ✅ Required | ✅ Required |
535
+ | Matches real layout | ✅ Automatically | ⚠️ Manual | ⚠️ Manual |
536
+ | Template data | ✅ `dummyData` | ❌ | ❌ |
537
+ | List mode | ✅ `dummyLength` / `as` | ❌ | ❌ |
538
+ | Suspense support | ✅ Native | | |
539
+ | Synchronized animation | ✅ One overlay | ⚠️ Per-element | ⚠️ Per-element |
540
+ | Zero layout shift | | ⚠️ | ⚠️ |
541
+ | Bundle size | ~3kb | ~5kb | ~12kb |
421
542
 
422
543
  ---
423
544
 
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  'use strict';
2
3
 
3
4
  var React2 = require('react');
@@ -133,9 +134,8 @@ var ShimmerOverlay = ({
133
134
  };
134
135
 
135
136
  // src/utils.ts
136
- var counter = 0;
137
137
  function generateShimmerKey(prefix = "shimmer") {
138
- return `${prefix}-clone-${++counter}`;
138
+ return prefix;
139
139
  }
140
140
  var FALLBACK_DIMENSIONS = {
141
141
  INPUT: { width: 200, height: 36 },
@@ -196,13 +196,23 @@ function isTraceable(el) {
196
196
  }
197
197
  return false;
198
198
  }
199
+ function isViewportLocked(el) {
200
+ const pos = window.getComputedStyle(el).position;
201
+ return pos === "fixed" || pos === "sticky";
202
+ }
203
+ var warnedContainers = /* @__PURE__ */ new WeakSet();
199
204
  function collectTraceableElements(root) {
200
- const result = [];
205
+ const traced = [];
206
+ let skippedFixed = 0;
201
207
  function walk(el) {
202
208
  if (el.hasAttribute("data-shimmer-ignore")) return;
203
209
  if (el.hasAttribute("data-shimmer-reporter")) return;
210
+ if (!el.hasAttribute("data-shimmer") && isViewportLocked(el)) {
211
+ skippedFixed += 1;
212
+ return;
213
+ }
204
214
  if (isTraceable(el)) {
205
- result.push(el);
215
+ traced.push(el);
206
216
  return;
207
217
  }
208
218
  for (let i = 0; i < el.children.length; i++) {
@@ -212,7 +222,7 @@ function collectTraceableElements(root) {
212
222
  for (let i = 0; i < root.children.length; i++) {
213
223
  walk(root.children[i]);
214
224
  }
215
- return result;
225
+ return { traced, skippedFixed };
216
226
  }
217
227
  function measureElement(el, containerRect, globalBorderRadius) {
218
228
  const elRect = el.getBoundingClientRect();
@@ -245,8 +255,14 @@ function measureElement(el, containerRect, globalBorderRadius) {
245
255
  function performTrace(container, globalBorderRadius, anchorRef) {
246
256
  const anchor = anchorRef?.current ?? container;
247
257
  const anchorRect = anchor.getBoundingClientRect();
248
- const elements = collectTraceableElements(container);
249
- return elements.map((el) => measureElement(el, anchorRect, globalBorderRadius)).filter((r) => r !== null && r.width > 0 && r.height > 0);
258
+ const { traced, skippedFixed } = collectTraceableElements(container);
259
+ if (skippedFixed > 0 && !warnedContainers.has(container)) {
260
+ warnedContainers.add(container);
261
+ console.warn(
262
+ `[shimmer-trace] Skipped ${skippedFixed} element(s) with position:fixed or position:sticky. Their coordinate space cannot follow the Master container during scroll, so the overlay block would drift. Render a nested <Shimmer> inside the fixed/sticky element if you need a skeleton there, or add data-shimmer to opt in (positioning may still drift on scroll).`
263
+ );
264
+ }
265
+ return traced.map((el) => measureElement(el, anchorRect, globalBorderRadius)).filter((r) => r !== null && r.width > 0 && r.height > 0);
250
266
  }
251
267
  function useTrace(containerRef, loading, globalBorderRadius, anchorRef) {
252
268
  const [rects, setRects] = React2.useState([]);
@@ -414,7 +430,7 @@ function MasterShimmer({
414
430
  return next;
415
431
  });
416
432
  }, []);
417
- React2__default.default.useEffect(() => {
433
+ React2.useInsertionEffect(() => {
418
434
  injectStyles();
419
435
  }, []);
420
436
  const tracedRects = useTrace(
@@ -597,5 +613,5 @@ exports.ShimmerSuspense = ShimmerSuspense;
597
613
  exports.createShimmer = createShimmer;
598
614
  exports.useIsShimmering = useIsShimmering;
599
615
  exports.useShimmerContext = useShimmerContext;
600
- //# sourceMappingURL=index.js.map
601
- //# sourceMappingURL=index.js.map
616
+ //# sourceMappingURL=index.cjs.map
617
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/ShimmerContext.tsx","../src/ShimmerOverlay.tsx","../src/utils.ts","../src/useTrace.ts","../src/styles.ts","../src/Shimmer.tsx","../src/createShimmer.tsx","../src/ShimmerSuspense.tsx"],"names":["createContext","useContext","jsx","React","useState","useCallback","useLayoutEffect","useId","useMemo","useRef","useInsertionEffect","jsxs","createElement"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { ReactNode } from 'react';\r\n\r\n/**\r\n * Represents a measured rectangle of a traced DOM element,\r\n * positioned relative to the Master Shimmer container.\r\n */\r\nexport interface ShimmerRect {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n borderRadius: string;\r\n}\r\n\r\n/** Available animation types for the shimmer effect. */\r\nexport type AnimationType =\r\n | 'wave'\r\n | 'pulse'\r\n | 'shine'\r\n | 'glow'\r\n | 'gradient';\r\n\r\n/** Configuration options for the shimmer effect (all optional). */\r\nexport interface ShimmerConfig {\r\n /** Animation style. Defaults to 'wave'. */\r\n animation?: AnimationType;\r\n /** Base color of the shimmer blocks. Defaults to '#e0e0e0'. */\r\n baseColor?: string;\r\n /** Highlight color of the shimmer animation. Defaults to '#f5f5f5'. */\r\n highlightColor?: string;\r\n /** Animation duration in seconds. Defaults to 1.5. */\r\n speed?: number;\r\n /** Global border-radius override. If omitted, auto-detected from each element (defaults to 4px if detection is 0px). */\r\n borderRadius?: string;\r\n /**\r\n * Keep container backgrounds, borders, and padding visible while loading.\r\n * When `true` (default), only text and media leaves are hidden via\r\n * `color:transparent` / `opacity:0` so card backgrounds, borders, and\r\n * spacing remain visible underneath the shimmer overlay.\r\n *\r\n * Set `false` for legacy behavior (`visibility:hidden` on whole tree).\r\n */\r\n preserveBackground?: boolean;\r\n}\r\n\r\n/** Props for the Shimmer component. */\r\nexport interface ShimmerProps extends ShimmerConfig {\r\n /** Whether the loading state is active. */\r\n loading?: boolean;\r\n /** The children to trace and render shimmer over. */\r\n children: ReactNode;\r\n /**\r\n * Number of placeholder clones to generate for list-like loading states.\r\n *\r\n * When `loading=true` and `dummyLength` is set, Shimmer grabs the first\r\n * available child (or a cached template from the last loaded render) and\r\n * clones it `dummyLength` times to produce skeleton placeholders.\r\n *\r\n * When `loading=false`, children are rendered as-is.\r\n */\r\n dummyLength?: number;\r\n /**\r\n * Props injected into each child element while `loading=true` so the\r\n * skeleton renders with realistic shape without requiring real data.\r\n *\r\n * Example:\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyData={{ user: { name: 'Loading...', role: '...', avatar: '' } }}\r\n * >\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * While loading, each direct child is cloned with these props merged on top\r\n * of its own props. Ignored when `loading=false`.\r\n */\r\n dummyData?: Record<string, any>;\r\n /**\r\n * Component used to auto-generate skeleton elements while `loading=true`.\r\n *\r\n * When set, Shimmer ignores `children` during loading and renders\r\n * `dummyLength` (defaults to 1) instances of `<as {...dummyData} />`\r\n * to derive shape. Real children render once `loading=false`.\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * as={MovieCard}\r\n * dummyData={{ movie: movieTemplate }}\r\n * dummyLength={10}\r\n * >\r\n * {movies.map((m) => <MovieCard movie={m} key={m.id} />)}\r\n * </Shimmer>\r\n * ```\r\n */\r\n as?: React.ComponentType<any>;\r\n /** Force this Shimmer to be a Master renderer even if nested inside another Shimmer. */\r\n stopPropagation?: boolean;\r\n /**\r\n * className applied to the Master container div.\r\n * Use to control layout (e.g. display:flex) without losing position:relative.\r\n */\r\n className?: string;\r\n /**\r\n * Inline styles merged into the Master container div.\r\n * position:relative is always applied; everything else is overridable.\r\n */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/** Default configuration values. */\r\nexport const DEFAULTS: Required<ShimmerConfig> = {\r\n animation: 'wave',\r\n baseColor: '#e0e0e0',\r\n highlightColor: '#f5f5f5',\r\n speed: 1.5,\r\n borderRadius: '',\r\n preserveBackground: true,\r\n};\r\n","\"use client\";\r\n\r\nimport { createContext, useContext, RefObject } from \"react\";\r\nimport { ShimmerRect, ShimmerConfig } from \"./types\";\r\n\r\nexport interface ShimmerContextValue {\r\n\tregister: (id: string, rects: ShimmerRect[]) => void;\r\n\tunregister: (id: string) => void;\r\n\t/** Ref object (not .current) so Reporters always read a fresh value. */\r\n\tmasterRef: RefObject<HTMLElement | null>;\r\n\tloading: boolean;\r\n\tconfig: Required<ShimmerConfig>;\r\n}\r\n\r\nexport const ShimmerContext = createContext<ShimmerContextValue | null>(null);\r\n\r\nexport function useShimmerContext(): ShimmerContextValue | null {\r\n\treturn useContext(ShimmerContext);\r\n}\r\n\r\n/**\r\n * True when rendered inside a ShimmerSuspense fallback (Option B).\r\n * Components use this to skip data fetching and return an empty shape.\r\n */\r\nexport const IsShimmeringContext = createContext<boolean>(false);\r\n\r\nexport function useIsShimmering(): boolean {\r\n\treturn useContext(IsShimmeringContext);\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { ShimmerRect, AnimationType } from './types';\r\n\r\ninterface ShimmerOverlayProps {\r\n rects: ShimmerRect[];\r\n animation: AnimationType;\r\n baseColor: string;\r\n highlightColor: string;\r\n speed: number;\r\n}\r\n\r\n/**\r\n * Returns animation-specific inline styles for each shimmer block.\r\n * For sweep-style animations (wave, shine), the colored gradient is rendered\r\n * as a child layer so the sweep can extend across the container in sync.\r\n */\r\nfunction getBlockStyles(\r\n animation: AnimationType,\r\n baseColor: string,\r\n highlightColor: string,\r\n speed: number,\r\n rect: ShimmerRect,\r\n): React.CSSProperties {\r\n const base: React.CSSProperties = {\r\n position: 'absolute',\r\n top: rect.y,\r\n left: rect.x,\r\n width: rect.width,\r\n height: rect.height,\r\n borderRadius: rect.borderRadius,\r\n overflow: 'hidden',\r\n };\r\n\r\n switch (animation) {\r\n case 'wave':\r\n case 'shine':\r\n return { ...base, background: baseColor };\r\n case 'pulse':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-pulse ${speed}s ease-in-out infinite`,\r\n };\r\n case 'glow':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-glow ${speed}s ease-in-out infinite`,\r\n };\r\n case 'gradient':\r\n return {\r\n ...base,\r\n backgroundImage: `linear-gradient(90deg, ${baseColor}, ${highlightColor}, ${baseColor})`,\r\n backgroundSize: '200% 100%',\r\n animation: `shimmer-gradient ${speed * 1.5}s ease-in-out infinite`,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Sweeping shine layer used by `wave` and `shine` animations.\r\n * Spans the full container width so the highlight sweeps in sync across all blocks.\r\n */\r\nconst SweepLayer: React.FC<{\r\n rect: ShimmerRect;\r\n highlightColor: string;\r\n speed: number;\r\n containerWidth: number;\r\n variant: 'wave' | 'shine';\r\n}> = ({ rect, highlightColor, speed, containerWidth, variant }) => {\r\n const isShine = variant === 'shine';\r\n return (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: -rect.x,\r\n width: containerWidth > 0 ? containerWidth : '100vw',\r\n height: '100%',\r\n background: isShine\r\n ? `linear-gradient(115deg, transparent 30%, ${highlightColor} 50%, transparent 70%)`\r\n : `linear-gradient(90deg, transparent 0%, ${highlightColor} 50%, transparent 100%)`,\r\n animation: `${isShine ? 'shimmer-shine' : 'shimmer-wave'} ${speed}s ease-in-out infinite`,\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * The overlay component rendered by the Master Shimmer.\r\n *\r\n * Renders one absolutely-positioned div per traced rect. Sweep-style\r\n * animations (`wave`, `shine`) get an additional gradient layer that spans\r\n * the container so the highlight passes across all blocks in sync.\r\n */\r\nexport const ShimmerOverlay: React.FC<ShimmerOverlayProps> = ({\r\n rects,\r\n animation,\r\n baseColor,\r\n highlightColor,\r\n speed,\r\n}) => {\r\n const overlayRef = React.useRef<HTMLDivElement>(null);\r\n const [containerWidth, setContainerWidth] = React.useState(0);\r\n\r\n React.useLayoutEffect(() => {\r\n if (!overlayRef.current?.parentElement) return;\r\n setContainerWidth(overlayRef.current.parentElement.offsetWidth);\r\n }, [rects]);\r\n\r\n if (rects.length === 0) return null;\r\n\r\n const isSweep = animation === 'wave' || animation === 'shine';\r\n\r\n return (\r\n <div\r\n ref={overlayRef}\r\n role=\"status\"\r\n aria-busy=\"true\"\r\n aria-label=\"Loading content\"\r\n data-shimmer-ignore=\"true\"\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n zIndex: 1,\r\n pointerEvents: 'none',\r\n visibility: 'visible',\r\n }}\r\n >\r\n {rects.map((rect, i) => (\r\n <div\r\n key={i}\r\n style={getBlockStyles(animation, baseColor, highlightColor, speed, rect)}\r\n >\r\n {isSweep && (\r\n <SweepLayer\r\n rect={rect}\r\n highlightColor={highlightColor}\r\n speed={speed}\r\n containerWidth={containerWidth}\r\n variant={animation as 'wave' | 'shine'}\r\n />\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * Generates a deterministic key for cloned elements.\r\n *\r\n * Prefix already includes the parent Shimmer's `useId()` plus a positional\r\n * index from the caller, so it is unique per render slot and stable across\r\n * SSR + client hydration. No module-scope counter — that caused hydration\r\n * mismatches and forced React to remount cloned children every render.\r\n */\r\nexport function generateShimmerKey(prefix: string = 'shimmer'): string {\r\n return prefix;\r\n}\r\n\r\n/**\r\n * Default fallback dimensions for common elements when their\r\n * measured dimensions are 0px (e.g., empty inputs, images not yet loaded).\r\n */\r\nexport const FALLBACK_DIMENSIONS: Record<string, { width: number; height: number }> = {\r\n INPUT: { width: 200, height: 36 },\r\n BUTTON: { width: 120, height: 36 },\r\n TEXTAREA: { width: 300, height: 80 },\r\n SELECT: { width: 200, height: 36 },\r\n IMG: { width: 100, height: 100 },\r\n H1: { width: 300, height: 36 },\r\n H2: { width: 260, height: 30 },\r\n H3: { width: 220, height: 26 },\r\n H4: { width: 200, height: 22 },\r\n H5: { width: 180, height: 20 },\r\n H6: { width: 160, height: 18 },\r\n P: { width: 250, height: 16 },\r\n SPAN: { width: 100, height: 16 },\r\n};\r\n","'use client';\r\n\r\nimport { useLayoutEffect, useState, RefObject, useCallback } from 'react';\r\nimport { ShimmerRect } from './types';\r\nimport { FALLBACK_DIMENSIONS } from './utils';\r\n\r\n/**\r\n * Tags that are always considered \"traceable\" leaf elements\r\n * whose dimensions should be captured for the shimmer overlay.\r\n */\r\nconst TRACEABLE_TAGS = new Set([\r\n // Text\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LI',\r\n 'LABEL', 'TD', 'TH', 'BLOCKQUOTE', 'CODE', 'PRE',\r\n // Media\r\n 'IMG', 'VIDEO', 'SVG', 'CANVAS', 'PICTURE',\r\n // Form\r\n 'INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',\r\n // Misc\r\n 'HR',\r\n]);\r\n\r\n/**\r\n * Determines if an element should be traced.\r\n * Explicit data attributes override automatic detection.\r\n */\r\nfunction isTraceable(el: Element): boolean {\r\n if (el.hasAttribute('data-shimmer-ignore')) return false;\r\n if (el.hasAttribute('data-shimmer')) return true;\r\n if (TRACEABLE_TAGS.has(el.tagName)) return true;\r\n\r\n // Leaf element with visible dimensions → trace it\r\n if (el.children.length === 0) {\r\n const rect = el.getBoundingClientRect();\r\n return rect.width > 0 && rect.height > 0;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Detects elements whose coordinate space cannot follow the Master\r\n * container during scroll. `position: fixed` and `position: sticky`\r\n * both live in a different scroll context (viewport / nearest scroll\r\n * container) than the Master, so any container-relative rect we compute\r\n * for them becomes stale on the first scroll.\r\n *\r\n * Returning `true` here causes the entire subtree under `el` to be\r\n * skipped, since descendants of a fixed/sticky element inherit the same\r\n * broken coordinate space.\r\n */\r\nfunction isViewportLocked(el: Element): boolean {\r\n const pos = window.getComputedStyle(el).position;\r\n return pos === 'fixed' || pos === 'sticky';\r\n}\r\n\r\n/**\r\n * Tracks Master containers we've already warned about, so the\r\n * console.warn fires once per container instead of on every resize-driven\r\n * re-trace. WeakSet keeps the dedupe noise-free across container churn —\r\n * a fresh Master gets one warning, period.\r\n */\r\nconst warnedContainers = new WeakSet<Element>();\r\n\r\ninterface CollectResult {\r\n traced: Element[];\r\n skippedFixed: number;\r\n}\r\n\r\n/**\r\n * Recursively walks the DOM tree and collects all traceable elements.\r\n *\r\n * Also reports how many elements were silently skipped because they used\r\n * `position: fixed` / `position: sticky`. Users can override this skip\r\n * by adding `data-shimmer` to the element, but the resulting overlay\r\n * block will drift on scroll — that's their choice to make.\r\n */\r\nfunction collectTraceableElements(root: Element): CollectResult {\r\n const traced: Element[] = [];\r\n let skippedFixed = 0;\r\n\r\n function walk(el: Element) {\r\n if (el.hasAttribute('data-shimmer-ignore')) return;\r\n if (el.hasAttribute('data-shimmer-reporter')) return; // Ignore nested reporters, they report their own rects\r\n\r\n // `data-shimmer` is an explicit opt-in — trust the user and trace.\r\n // Without it, fixed/sticky elements are skipped entirely (including\r\n // their descendants, which share the broken coordinate space).\r\n if (!el.hasAttribute('data-shimmer') && isViewportLocked(el)) {\r\n skippedFixed += 1;\r\n return;\r\n }\r\n\r\n if (isTraceable(el)) {\r\n traced.push(el);\r\n return; // Don't recurse into traced elements\r\n }\r\n\r\n for (let i = 0; i < el.children.length; i++) {\r\n walk(el.children[i]);\r\n }\r\n }\r\n\r\n for (let i = 0; i < root.children.length; i++) {\r\n walk(root.children[i]);\r\n }\r\n\r\n return { traced, skippedFixed };\r\n}\r\n\r\n/**\r\n * Measures an element and returns its ShimmerRect relative to the container.\r\n */\r\nfunction measureElement(\r\n el: Element,\r\n containerRect: DOMRect,\r\n globalBorderRadius?: string,\r\n): ShimmerRect | null {\r\n const elRect = el.getBoundingClientRect();\r\n\r\n // If the element is display: none or detached, getBoundingClientRect returns all zeros.\r\n // We must not trace it, otherwise it ends up at the left edge of the screen.\r\n if (elRect.width === 0 && elRect.height === 0 && elRect.left === 0 && elRect.top === 0) {\r\n return null;\r\n }\r\n\r\n const computedStyle = window.getComputedStyle(el);\r\n let borderRadius = globalBorderRadius || computedStyle.borderRadius;\r\n\r\n // If the element has no border radius (common for text tags),\r\n // apply a small default to avoid sharp edges in the shimmer.\r\n const isZero = !borderRadius || borderRadius === 'none' || borderRadius.split(' ').every(v => v === '0' || v === '0px' || v === '0%');\r\n if (isZero) {\r\n borderRadius = '4px';\r\n }\r\n\r\n let width = elRect.width;\r\n let height = elRect.height;\r\n\r\n // Apply fallback dimensions if element has 0 size but is actually visible (e.g. empty inline element)\r\n if (width === 0 || height === 0) {\r\n const fallback = FALLBACK_DIMENSIONS[el.tagName];\r\n if (fallback) {\r\n width = width || fallback.width;\r\n height = height || fallback.height;\r\n }\r\n }\r\n\r\n return {\r\n x: elRect.left - containerRect.left,\r\n y: elRect.top - containerRect.top,\r\n width,\r\n height,\r\n borderRadius,\r\n };\r\n}\r\n\r\n/**\r\n * Performs a full trace of all traceable elements within the container.\r\n *\r\n * @param anchorRef - When provided (Reporter mode), elements are measured\r\n * relative to this element instead of the container. Allows Reporter's\r\n * wrapper to use display:contents without breaking measurement.\r\n */\r\nfunction performTrace(\r\n container: HTMLElement,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const anchor = anchorRef?.current ?? container;\r\n const anchorRect = anchor.getBoundingClientRect();\r\n const { traced, skippedFixed } = collectTraceableElements(container);\r\n\r\n if (skippedFixed > 0 && !warnedContainers.has(container)) {\r\n warnedContainers.add(container);\r\n // eslint-disable-next-line no-console\r\n console.warn(\r\n `[shimmer-trace] Skipped ${skippedFixed} element(s) with ` +\r\n `position:fixed or position:sticky. Their coordinate space ` +\r\n `cannot follow the Master container during scroll, so the overlay ` +\r\n `block would drift. Render a nested <Shimmer> inside the fixed/sticky ` +\r\n `element if you need a skeleton there, or add data-shimmer to opt in ` +\r\n `(positioning may still drift on scroll).`,\r\n );\r\n }\r\n\r\n return traced\r\n .map((el) => measureElement(el, anchorRect, globalBorderRadius))\r\n .filter((r): r is ShimmerRect => r !== null && r.width > 0 && r.height > 0);\r\n}\r\n\r\n/**\r\n * Hook that traces all visible leaf DOM elements within a container\r\n * and returns their measured ShimmerRects.\r\n *\r\n * Uses ResizeObserver to re-trace on container resize.\r\n *\r\n * @param anchorRef - When set, rects are relative to this element (Master).\r\n * Used by Reporter so its display:contents wrapper doesn't break measurement.\r\n */\r\nexport function useTrace(\r\n containerRef: RefObject<HTMLElement | null>,\r\n loading: boolean,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const [rects, setRects] = useState<ShimmerRect[]>([]);\r\n\r\n const trace = useCallback(() => {\r\n if (!containerRef.current) return;\r\n const traced = performTrace(containerRef.current, globalBorderRadius, anchorRef);\r\n setRects(traced);\r\n }, [containerRef, globalBorderRadius, anchorRef]);\r\n\r\n useLayoutEffect(() => {\r\n if (!loading || !containerRef.current) {\r\n setRects([]);\r\n return;\r\n }\r\n\r\n // Initial trace\r\n trace();\r\n\r\n // Re-trace on resize\r\n const observer = new ResizeObserver(() => {\r\n trace();\r\n });\r\n observer.observe(containerRef.current);\r\n\r\n return () => observer.disconnect();\r\n }, [loading, trace]);\r\n\r\n return rects;\r\n}\r\n","const SHIMMER_STYLES_ID = 'shimmer-trace-styles';\r\n\r\nconst CSS = `\r\n@keyframes shimmer-wave {\r\n 0% { transform: translateX(-100%); }\r\n 100% { transform: translateX(100%); }\r\n}\r\n\r\n@keyframes shimmer-pulse {\r\n 0%, 100% { opacity: 0.4; }\r\n 50% { opacity: 1; }\r\n}\r\n\r\n@keyframes shimmer-shine {\r\n 0% { transform: translateX(-150%) skewX(-20deg); }\r\n 100% { transform: translateX(150%) skewX(-20deg); }\r\n}\r\n\r\n@keyframes shimmer-glow {\r\n 0%, 100% { filter: brightness(1); }\r\n 50% { filter: brightness(1.35); }\r\n}\r\n\r\n@keyframes shimmer-gradient {\r\n 0% { background-position: 0% 50%; }\r\n 50% { background-position: 100% 50%; }\r\n 100% { background-position: 0% 50%; }\r\n}\r\n\r\n/* preserveBackground mode: hide text + media but keep container styles */\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,td,th,blockquote,code,pre,strong,em,small) {\r\n color: transparent !important;\r\n text-shadow: none !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(img,video,svg,canvas,picture) {\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(input,textarea,select,button) {\r\n color: transparent !important;\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] {\r\n pointer-events: none !important;\r\n user-select: none !important;\r\n}\r\n`;\r\n\r\n/**\r\n * Injects the shimmer keyframe animations into the document head.\r\n * Safe to call multiple times — only injects once.\r\n */\r\nexport function injectStyles(): void {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById(SHIMMER_STYLES_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = SHIMMER_STYLES_ID;\r\n style.textContent = CSS;\r\n document.head.appendChild(style);\r\n}\r\n","'use client';\r\n\r\nimport React, { useRef, useCallback, useState, useId, useMemo, useInsertionEffect } from \"react\";\r\nimport { ShimmerProps, ShimmerRect, DEFAULTS } from \"./types\";\r\nimport { ShimmerContext, useShimmerContext } from \"./ShimmerContext\";\r\nimport { ShimmerOverlay } from \"./ShimmerOverlay\";\r\nimport { useTrace } from \"./useTrace\";\r\nimport { injectStyles } from \"./styles\";\r\nimport { generateShimmerKey } from \"./utils\";\r\n\r\n/**\r\n * The main Shimmer component.\r\n *\r\n * Auto-detects **Master** (no parent Shimmer) vs **Reporter** (nested).\r\n * - Master: renders children hidden, traces DOM, paints overlay.\r\n * - Reporter: measures own rects, reports to parent Master.\r\n *\r\n * ### Skeleton shape via `dummyData`\r\n *\r\n * Pass `dummyData` so children render with realistic data while loading.\r\n * No render-prop, no manual `data || fallback` in JSX.\r\n *\r\n * ```tsx\r\n * const userTemplate = { name: 'Loading...', role: '...', avatar: '' };\r\n *\r\n * <Shimmer loading={loading} dummyData={{ user: userTemplate }}>\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * ### List mode (`dummyLength`)\r\n *\r\n * Combined with `dummyData`, clones the first child N times with\r\n * template props merged in:\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyLength={5}\r\n * dummyData={{ fruit: { name: 'xxxxx', price: '$0.00' } }}\r\n * >\r\n * <FruitCard fruit={undefined as any} />\r\n * </Shimmer>\r\n * ```\r\n */\r\nexport function Shimmer({\r\n\tloading = false,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tstopPropagation = false,\r\n\tanimation,\r\n\tbaseColor,\r\n\thighlightColor,\r\n\tspeed,\r\n\tborderRadius,\r\n\tpreserveBackground,\r\n\tclassName,\r\n\tstyle,\r\n}: ShimmerProps) {\r\n\tconst parentContext = useShimmerContext();\r\n\tconst isMaster = !parentContext || stopPropagation;\r\n\tconst id = useId();\r\n\r\n\tconst config = useMemo(\r\n\t\t() => ({\r\n\t\t\tanimation:\r\n\t\t\t\tanimation ?? parentContext?.config.animation ?? DEFAULTS.animation,\r\n\t\t\tbaseColor:\r\n\t\t\t\tbaseColor ?? parentContext?.config.baseColor ?? DEFAULTS.baseColor,\r\n\t\t\thighlightColor:\r\n\t\t\t\thighlightColor ??\r\n\t\t\t\tparentContext?.config.highlightColor ??\r\n\t\t\t\tDEFAULTS.highlightColor,\r\n\t\t\tspeed: speed ?? parentContext?.config.speed ?? DEFAULTS.speed,\r\n\t\t\tborderRadius:\r\n\t\t\t\tborderRadius ??\r\n\t\t\t\tparentContext?.config.borderRadius ??\r\n\t\t\t\tDEFAULTS.borderRadius,\r\n\t\t\tpreserveBackground:\r\n\t\t\t\tpreserveBackground ??\r\n\t\t\t\tparentContext?.config.preserveBackground ??\r\n\t\t\t\tDEFAULTS.preserveBackground,\r\n\t\t}),\r\n\t\t[\r\n\t\t\tanimation,\r\n\t\t\tbaseColor,\r\n\t\t\thighlightColor,\r\n\t\t\tspeed,\r\n\t\t\tborderRadius,\r\n\t\t\tpreserveBackground,\r\n\t\t\tparentContext?.config,\r\n\t\t],\r\n\t);\r\n\r\n\tif (isMaster) {\r\n\t\treturn (\r\n\t\t\t<MasterShimmer\r\n\t\t\t\tid={id}\r\n\t\t\t\tloading={loading}\r\n\t\t\t\tconfig={config}\r\n\t\t\t\tdummyLength={dummyLength}\r\n\t\t\t\tdummyData={dummyData}\r\n\t\t\t\tas={as}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={style}\r\n\t\t\t>\r\n\t\t\t\t{children}\r\n\t\t\t</MasterShimmer>\r\n\t\t);\r\n\t}\r\n\r\n\treturn (\r\n\t\t<ReporterShimmer\r\n\t\t\tid={id}\r\n\t\t\tparentContext={parentContext!}\r\n\t\t\tconfig={config}\r\n\t\t\tdummyLength={dummyLength}\r\n\t\t\tdummyData={dummyData}\r\n\t\t\tas={as}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</ReporterShimmer>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Master ─────────────────── */\r\n\r\ninterface MasterShimmerProps {\r\n\tid: string;\r\n\tloading: boolean;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\nfunction MasterShimmer({\r\n\tid,\r\n\tloading,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tclassName,\r\n\tstyle,\r\n}: MasterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst [reporterRects, setReporterRects] = useState<\r\n\t\tRecord<string, ShimmerRect[]>\r\n\t>({});\r\n\r\n\tconst register = useCallback((rid: string, rects: ShimmerRect[]) => {\r\n\t\tsetReporterRects((prev) => ({ ...prev, [rid]: rects }));\r\n\t}, []);\r\n\r\n\tconst unregister = useCallback((rid: string) => {\r\n\t\tsetReporterRects((prev) => {\r\n\t\t\tconst next = { ...prev };\r\n\t\t\tdelete next[rid];\r\n\t\t\treturn next;\r\n\t\t});\r\n\t}, []);\r\n\r\n\tuseInsertionEffect(() => {\r\n\t\tinjectStyles();\r\n\t}, []);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tloading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t);\r\n\r\n\tconst allRects = useMemo(() => {\r\n\t\tconst reported = Object.values(reporterRects).flat();\r\n\t\treturn [...tracedRects, ...reported];\r\n\t}, [tracedRects, reporterRects]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\tconst contextValue = useMemo(\r\n\t\t() => ({\r\n\t\t\tregister,\r\n\t\t\tunregister,\r\n\t\t\tmasterRef: containerRef,\r\n\t\t\tloading,\r\n\t\t\tconfig,\r\n\t\t}),\r\n\t\t[register, unregister, loading, config],\r\n\t);\r\n\r\n\treturn (\r\n\t\t<ShimmerContext.Provider value={contextValue}>\r\n\t\t\t<div\r\n\t\t\t\tref={containerRef}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={{\r\n\t\t\t\t\tposition: \"relative\",\r\n\t\t\t\t\tvisibility:\r\n\t\t\t\t\t\tloading && !config.preserveBackground ? \"hidden\" : undefined,\r\n\t\t\t\t\t...style,\r\n\t\t\t\t}}\r\n\t\t\t\taria-hidden={loading || undefined}\r\n\t\t\t\tdata-shimmer-master\r\n\t\t\t\tdata-shimmer-preserve-bg={\r\n\t\t\t\t\tloading && config.preserveBackground ? \"true\" : undefined\r\n\t\t\t\t}\r\n\t\t\t>\r\n\t\t\t\t{renderedChildren}\r\n\r\n\t\t\t\t{loading && (\r\n\t\t\t\t\t<ShimmerOverlay\r\n\t\t\t\t\t\trects={allRects}\r\n\t\t\t\t\t\tanimation={config.animation}\r\n\t\t\t\t\t\tbaseColor={config.baseColor}\r\n\t\t\t\t\t\thighlightColor={config.highlightColor}\r\n\t\t\t\t\t\tspeed={config.speed}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t</div>\r\n\t\t</ShimmerContext.Provider>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Reporter ─────────────────── */\r\n\r\ninterface ReporterShimmerProps {\r\n\tid: string;\r\n\tparentContext: NonNullable<ReturnType<typeof useShimmerContext>>;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n}\r\n\r\nfunction ReporterShimmer({\r\n\tid,\r\n\tparentContext,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n}: ReporterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tparentContext.loading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t\tparentContext.masterRef,\r\n\t);\r\n\r\n\tReact.useLayoutEffect(() => {\r\n\t\tif (!parentContext.loading || tracedRects.length === 0) {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tparentContext.register(id, tracedRects);\r\n\t\treturn () => {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t};\r\n\t}, [tracedRects, parentContext, id]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading: parentContext.loading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<div\r\n\t\t\tref={containerRef}\r\n\t\t\tdata-shimmer-reporter\r\n\t\t\tstyle={{ display: \"contents\" }}\r\n\t\t>\r\n\t\t\t{renderedChildren}\r\n\t\t</div>\r\n\t);\r\n}\r\n\r\n/* ─────────────── Skeleton Children ─────────────── */\r\n\r\ninterface UseSkeletonChildrenParams {\r\n\tloading: boolean;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tid: string;\r\n}\r\n\r\n/**\r\n * Build the rendered children tree.\r\n *\r\n * Priority during `loading=true`:\r\n * 1. `as` set → render `dummyLength` (or 1) instances of `<as {...dummyData} />`.\r\n * Children ignored. Cold-start safe.\r\n * 2. `dummyData` set + children present → clone each child merging\r\n * dummyData over its props. If `dummyLength` set, clone first\r\n * templated child N times.\r\n * 3. None → pass children through (e.g. `useIsShimmering` flow).\r\n *\r\n * `loading=false` → children untouched.\r\n */\r\nfunction useSkeletonChildren({\r\n\tloading,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tid,\r\n}: UseSkeletonChildrenParams): React.ReactNode {\r\n\tif (!loading) return children;\r\n\r\n\tif (as) {\r\n\t\tconst count = dummyLength && dummyLength > 0 ? dummyLength : 1;\r\n\t\tconst Component = as;\r\n\t\treturn Array.from({ length: count }, (_, i) => (\r\n\t\t\t<Component\r\n\t\t\t\t{...(dummyData || {})}\r\n\t\t\t\tkey={generateShimmerKey(`${id}-as-${i}`)}\r\n\t\t\t/>\r\n\t\t));\r\n\t}\r\n\r\n\tconst childArray = React.Children.toArray(children);\r\n\r\n\tconst templated = childArray.map((c, i) => {\r\n\t\tif (!React.isValidElement(c)) return c;\r\n\t\tconst key = generateShimmerKey(`${id}-tpl-${i}`);\r\n\t\tconst props = dummyData ? { ...dummyData, key } : { key };\r\n\t\treturn React.cloneElement(c as React.ReactElement, props as any);\r\n\t});\r\n\r\n\tif (dummyLength && dummyLength > 0) {\r\n\t\tconst first = templated.find((c) => React.isValidElement(c)) as\r\n\t\t\t| React.ReactElement\r\n\t\t\t| undefined;\r\n\t\tif (!first) return null;\r\n\t\treturn Array.from({ length: dummyLength }, (_, i) =>\r\n\t\t\tReact.cloneElement(first, {\r\n\t\t\t\tkey: generateShimmerKey(`${id}-clone-${i}`),\r\n\t\t\t} as any),\r\n\t\t);\r\n\t}\r\n\r\n\treturn templated;\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { ShimmerConfig, ShimmerProps, DEFAULTS } from './types';\r\n\r\n/**\r\n * Factory function to create a pre-configured Shimmer component.\r\n * Avoids \"Provider Hell\" by baking config into the returned component.\r\n *\r\n * All config properties are optional — defaults are used for anything\r\n * not specified.\r\n *\r\n * @example\r\n * ```tsx\r\n * const AppShimmer = createShimmer({\r\n * animation: 'pulse',\r\n * baseColor: '#1a1a2e',\r\n * highlightColor: '#16213e',\r\n * speed: 2,\r\n * });\r\n *\r\n * <AppShimmer loading={isLoading}>\r\n * <MyComponent />\r\n * </AppShimmer>\r\n * ```\r\n */\r\nexport function createShimmer(config: ShimmerConfig = {}) {\r\n const mergedConfig: Required<ShimmerConfig> = {\r\n animation: config.animation ?? DEFAULTS.animation,\r\n baseColor: config.baseColor ?? DEFAULTS.baseColor,\r\n highlightColor: config.highlightColor ?? DEFAULTS.highlightColor,\r\n speed: config.speed ?? DEFAULTS.speed,\r\n borderRadius: config.borderRadius ?? DEFAULTS.borderRadius,\r\n preserveBackground: config.preserveBackground ?? DEFAULTS.preserveBackground,\r\n };\r\n\r\n function ConfiguredShimmer(props: Omit<ShimmerProps, keyof ShimmerConfig> & Partial<ShimmerConfig>) {\r\n return (\r\n <Shimmer\r\n {...mergedConfig}\r\n {...props}\r\n />\r\n );\r\n }\r\n\r\n // Removed ConfiguredShimmer.displayName\r\n return ConfiguredShimmer;\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { IsShimmeringContext } from './ShimmerContext';\r\nimport { ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerSuspenseProps extends ShimmerConfig {\r\n children: React.ReactNode;\r\n /**\r\n * Explicit skeleton template. Rendered hidden and traced for shimmer shape.\r\n *\r\n * Preferred — pass the same component with no data props:\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * If omitted, falls back to Option B: children are re-rendered with\r\n * `useIsShimmering()=true` so they can return an empty shape themselves.\r\n */\r\n template?: React.ReactNode;\r\n}\r\n\r\n/**\r\n * Suspense boundary that automatically shows a shimmer skeleton while\r\n * children are suspended (e.g. useSuspenseQuery, use(promise), etc).\r\n *\r\n * **Option A — explicit template (preferred):**\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * **Option B — useIsShimmering hook (no template):**\r\n * ```tsx\r\n * function UserCard() {\r\n * const isShimmering = useIsShimmering();\r\n * const data = isShimmering ? null : useSuspenseQuery(...);\r\n * return <div><h3>{data?.name}</h3></div>;\r\n * }\r\n *\r\n * <ShimmerSuspense>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n * Components must use `useIsShimmering()` to skip data fetching in shimmer mode,\r\n * otherwise they will also suspend inside the fallback (causing an empty skeleton).\r\n */\r\nexport function ShimmerSuspense({\r\n children,\r\n template,\r\n ...shimmerConfig\r\n}: ShimmerSuspenseProps) {\r\n const skeletonContent =\r\n template !== undefined ? (\r\n template\r\n ) : (\r\n <IsShimmeringContext.Provider value={true}>\r\n {children}\r\n </IsShimmeringContext.Provider>\r\n );\r\n\r\n return (\r\n <React.Suspense\r\n fallback={\r\n <Shimmer loading={true} {...shimmerConfig}>\r\n {skeletonContent}\r\n </Shimmer>\r\n }\r\n >\r\n {children}\r\n </React.Suspense>\r\n );\r\n}\r\n"]}
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
- import React2, { createContext, useContext, useId, useMemo, useRef, useState, useCallback, createElement, useLayoutEffect } from 'react';
1
+ 'use client';
2
+ import React2, { createContext, useContext, useId, useMemo, useRef, useState, useCallback, useInsertionEffect, createElement, useLayoutEffect } from 'react';
2
3
  import { jsx, jsxs } from 'react/jsx-runtime';
3
4
 
4
5
  // src/Shimmer.tsx
@@ -127,9 +128,8 @@ var ShimmerOverlay = ({
127
128
  };
128
129
 
129
130
  // src/utils.ts
130
- var counter = 0;
131
131
  function generateShimmerKey(prefix = "shimmer") {
132
- return `${prefix}-clone-${++counter}`;
132
+ return prefix;
133
133
  }
134
134
  var FALLBACK_DIMENSIONS = {
135
135
  INPUT: { width: 200, height: 36 },
@@ -190,13 +190,23 @@ function isTraceable(el) {
190
190
  }
191
191
  return false;
192
192
  }
193
+ function isViewportLocked(el) {
194
+ const pos = window.getComputedStyle(el).position;
195
+ return pos === "fixed" || pos === "sticky";
196
+ }
197
+ var warnedContainers = /* @__PURE__ */ new WeakSet();
193
198
  function collectTraceableElements(root) {
194
- const result = [];
199
+ const traced = [];
200
+ let skippedFixed = 0;
195
201
  function walk(el) {
196
202
  if (el.hasAttribute("data-shimmer-ignore")) return;
197
203
  if (el.hasAttribute("data-shimmer-reporter")) return;
204
+ if (!el.hasAttribute("data-shimmer") && isViewportLocked(el)) {
205
+ skippedFixed += 1;
206
+ return;
207
+ }
198
208
  if (isTraceable(el)) {
199
- result.push(el);
209
+ traced.push(el);
200
210
  return;
201
211
  }
202
212
  for (let i = 0; i < el.children.length; i++) {
@@ -206,7 +216,7 @@ function collectTraceableElements(root) {
206
216
  for (let i = 0; i < root.children.length; i++) {
207
217
  walk(root.children[i]);
208
218
  }
209
- return result;
219
+ return { traced, skippedFixed };
210
220
  }
211
221
  function measureElement(el, containerRect, globalBorderRadius) {
212
222
  const elRect = el.getBoundingClientRect();
@@ -239,8 +249,14 @@ function measureElement(el, containerRect, globalBorderRadius) {
239
249
  function performTrace(container, globalBorderRadius, anchorRef) {
240
250
  const anchor = anchorRef?.current ?? container;
241
251
  const anchorRect = anchor.getBoundingClientRect();
242
- const elements = collectTraceableElements(container);
243
- return elements.map((el) => measureElement(el, anchorRect, globalBorderRadius)).filter((r) => r !== null && r.width > 0 && r.height > 0);
252
+ const { traced, skippedFixed } = collectTraceableElements(container);
253
+ if (skippedFixed > 0 && !warnedContainers.has(container)) {
254
+ warnedContainers.add(container);
255
+ console.warn(
256
+ `[shimmer-trace] Skipped ${skippedFixed} element(s) with position:fixed or position:sticky. Their coordinate space cannot follow the Master container during scroll, so the overlay block would drift. Render a nested <Shimmer> inside the fixed/sticky element if you need a skeleton there, or add data-shimmer to opt in (positioning may still drift on scroll).`
257
+ );
258
+ }
259
+ return traced.map((el) => measureElement(el, anchorRect, globalBorderRadius)).filter((r) => r !== null && r.width > 0 && r.height > 0);
244
260
  }
245
261
  function useTrace(containerRef, loading, globalBorderRadius, anchorRef) {
246
262
  const [rects, setRects] = useState([]);
@@ -408,7 +424,7 @@ function MasterShimmer({
408
424
  return next;
409
425
  });
410
426
  }, []);
411
- React2.useEffect(() => {
427
+ useInsertionEffect(() => {
412
428
  injectStyles();
413
429
  }, []);
414
430
  const tracedRects = useTrace(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/ShimmerContext.tsx","../src/ShimmerOverlay.tsx","../src/utils.ts","../src/useTrace.ts","../src/styles.ts","../src/Shimmer.tsx","../src/createShimmer.tsx","../src/ShimmerSuspense.tsx"],"names":["React","jsx","useState","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { ReactNode } from 'react';\r\n\r\n/**\r\n * Represents a measured rectangle of a traced DOM element,\r\n * positioned relative to the Master Shimmer container.\r\n */\r\nexport interface ShimmerRect {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n borderRadius: string;\r\n}\r\n\r\n/** Available animation types for the shimmer effect. */\r\nexport type AnimationType =\r\n | 'wave'\r\n | 'pulse'\r\n | 'shine'\r\n | 'glow'\r\n | 'gradient';\r\n\r\n/** Configuration options for the shimmer effect (all optional). */\r\nexport interface ShimmerConfig {\r\n /** Animation style. Defaults to 'wave'. */\r\n animation?: AnimationType;\r\n /** Base color of the shimmer blocks. Defaults to '#e0e0e0'. */\r\n baseColor?: string;\r\n /** Highlight color of the shimmer animation. Defaults to '#f5f5f5'. */\r\n highlightColor?: string;\r\n /** Animation duration in seconds. Defaults to 1.5. */\r\n speed?: number;\r\n /** Global border-radius override. If omitted, auto-detected from each element (defaults to 4px if detection is 0px). */\r\n borderRadius?: string;\r\n /**\r\n * Keep container backgrounds, borders, and padding visible while loading.\r\n * When `true` (default), only text and media leaves are hidden via\r\n * `color:transparent` / `opacity:0` so card backgrounds, borders, and\r\n * spacing remain visible underneath the shimmer overlay.\r\n *\r\n * Set `false` for legacy behavior (`visibility:hidden` on whole tree).\r\n */\r\n preserveBackground?: boolean;\r\n}\r\n\r\n/** Props for the Shimmer component. */\r\nexport interface ShimmerProps extends ShimmerConfig {\r\n /** Whether the loading state is active. */\r\n loading?: boolean;\r\n /** The children to trace and render shimmer over. */\r\n children: ReactNode;\r\n /**\r\n * Number of placeholder clones to generate for list-like loading states.\r\n *\r\n * When `loading=true` and `dummyLength` is set, Shimmer grabs the first\r\n * available child (or a cached template from the last loaded render) and\r\n * clones it `dummyLength` times to produce skeleton placeholders.\r\n *\r\n * When `loading=false`, children are rendered as-is.\r\n */\r\n dummyLength?: number;\r\n /**\r\n * Props injected into each child element while `loading=true` so the\r\n * skeleton renders with realistic shape without requiring real data.\r\n *\r\n * Example:\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyData={{ user: { name: 'Loading...', role: '...', avatar: '' } }}\r\n * >\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * While loading, each direct child is cloned with these props merged on top\r\n * of its own props. Ignored when `loading=false`.\r\n */\r\n dummyData?: Record<string, any>;\r\n /**\r\n * Component used to auto-generate skeleton elements while `loading=true`.\r\n *\r\n * When set, Shimmer ignores `children` during loading and renders\r\n * `dummyLength` (defaults to 1) instances of `<as {...dummyData} />`\r\n * to derive shape. Real children render once `loading=false`.\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * as={MovieCard}\r\n * dummyData={{ movie: movieTemplate }}\r\n * dummyLength={10}\r\n * >\r\n * {movies.map((m) => <MovieCard movie={m} key={m.id} />)}\r\n * </Shimmer>\r\n * ```\r\n */\r\n as?: React.ComponentType<any>;\r\n /** Force this Shimmer to be a Master renderer even if nested inside another Shimmer. */\r\n stopPropagation?: boolean;\r\n /**\r\n * className applied to the Master container div.\r\n * Use to control layout (e.g. display:flex) without losing position:relative.\r\n */\r\n className?: string;\r\n /**\r\n * Inline styles merged into the Master container div.\r\n * position:relative is always applied; everything else is overridable.\r\n */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/** Default configuration values. */\r\nexport const DEFAULTS: Required<ShimmerConfig> = {\r\n animation: 'wave',\r\n baseColor: '#e0e0e0',\r\n highlightColor: '#f5f5f5',\r\n speed: 1.5,\r\n borderRadius: '',\r\n preserveBackground: true,\r\n};\r\n","import { createContext, useContext, RefObject } from 'react';\r\nimport { ShimmerRect, ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerContextValue {\r\n register: (id: string, rects: ShimmerRect[]) => void;\r\n unregister: (id: string) => void;\r\n /** Ref object (not .current) so Reporters always read a fresh value. */\r\n masterRef: RefObject<HTMLElement | null>;\r\n loading: boolean;\r\n config: Required<ShimmerConfig>;\r\n}\r\n\r\nexport const ShimmerContext = createContext<ShimmerContextValue | null>(null);\r\n\r\nexport function useShimmerContext(): ShimmerContextValue | null {\r\n return useContext(ShimmerContext);\r\n}\r\n\r\n/**\r\n * True when rendered inside a ShimmerSuspense fallback (Option B).\r\n * Components use this to skip data fetching and return an empty shape.\r\n */\r\nexport const IsShimmeringContext = createContext<boolean>(false);\r\n\r\nexport function useIsShimmering(): boolean {\r\n return useContext(IsShimmeringContext);\r\n}\r\n","import React from 'react';\r\nimport { ShimmerRect, AnimationType } from './types';\r\n\r\ninterface ShimmerOverlayProps {\r\n rects: ShimmerRect[];\r\n animation: AnimationType;\r\n baseColor: string;\r\n highlightColor: string;\r\n speed: number;\r\n}\r\n\r\n/**\r\n * Returns animation-specific inline styles for each shimmer block.\r\n * For sweep-style animations (wave, shine), the colored gradient is rendered\r\n * as a child layer so the sweep can extend across the container in sync.\r\n */\r\nfunction getBlockStyles(\r\n animation: AnimationType,\r\n baseColor: string,\r\n highlightColor: string,\r\n speed: number,\r\n rect: ShimmerRect,\r\n): React.CSSProperties {\r\n const base: React.CSSProperties = {\r\n position: 'absolute',\r\n top: rect.y,\r\n left: rect.x,\r\n width: rect.width,\r\n height: rect.height,\r\n borderRadius: rect.borderRadius,\r\n overflow: 'hidden',\r\n };\r\n\r\n switch (animation) {\r\n case 'wave':\r\n case 'shine':\r\n return { ...base, background: baseColor };\r\n case 'pulse':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-pulse ${speed}s ease-in-out infinite`,\r\n };\r\n case 'glow':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-glow ${speed}s ease-in-out infinite`,\r\n };\r\n case 'gradient':\r\n return {\r\n ...base,\r\n backgroundImage: `linear-gradient(90deg, ${baseColor}, ${highlightColor}, ${baseColor})`,\r\n backgroundSize: '200% 100%',\r\n animation: `shimmer-gradient ${speed * 1.5}s ease-in-out infinite`,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Sweeping shine layer used by `wave` and `shine` animations.\r\n * Spans the full container width so the highlight sweeps in sync across all blocks.\r\n */\r\nconst SweepLayer: React.FC<{\r\n rect: ShimmerRect;\r\n highlightColor: string;\r\n speed: number;\r\n containerWidth: number;\r\n variant: 'wave' | 'shine';\r\n}> = ({ rect, highlightColor, speed, containerWidth, variant }) => {\r\n const isShine = variant === 'shine';\r\n return (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: -rect.x,\r\n width: containerWidth > 0 ? containerWidth : '100vw',\r\n height: '100%',\r\n background: isShine\r\n ? `linear-gradient(115deg, transparent 30%, ${highlightColor} 50%, transparent 70%)`\r\n : `linear-gradient(90deg, transparent 0%, ${highlightColor} 50%, transparent 100%)`,\r\n animation: `${isShine ? 'shimmer-shine' : 'shimmer-wave'} ${speed}s ease-in-out infinite`,\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * The overlay component rendered by the Master Shimmer.\r\n *\r\n * Renders one absolutely-positioned div per traced rect. Sweep-style\r\n * animations (`wave`, `shine`) get an additional gradient layer that spans\r\n * the container so the highlight passes across all blocks in sync.\r\n */\r\nexport const ShimmerOverlay: React.FC<ShimmerOverlayProps> = ({\r\n rects,\r\n animation,\r\n baseColor,\r\n highlightColor,\r\n speed,\r\n}) => {\r\n const overlayRef = React.useRef<HTMLDivElement>(null);\r\n const [containerWidth, setContainerWidth] = React.useState(0);\r\n\r\n React.useLayoutEffect(() => {\r\n if (!overlayRef.current?.parentElement) return;\r\n setContainerWidth(overlayRef.current.parentElement.offsetWidth);\r\n }, [rects]);\r\n\r\n if (rects.length === 0) return null;\r\n\r\n const isSweep = animation === 'wave' || animation === 'shine';\r\n\r\n return (\r\n <div\r\n ref={overlayRef}\r\n role=\"status\"\r\n aria-busy=\"true\"\r\n aria-label=\"Loading content\"\r\n data-shimmer-ignore=\"true\"\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n zIndex: 1,\r\n pointerEvents: 'none',\r\n visibility: 'visible',\r\n }}\r\n >\r\n {rects.map((rect, i) => (\r\n <div\r\n key={i}\r\n style={getBlockStyles(animation, baseColor, highlightColor, speed, rect)}\r\n >\r\n {isSweep && (\r\n <SweepLayer\r\n rect={rect}\r\n highlightColor={highlightColor}\r\n speed={speed}\r\n containerWidth={containerWidth}\r\n variant={animation as 'wave' | 'shine'}\r\n />\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * Generates a unique key for cloned elements to prevent\r\n * React \"missing key\" warnings during loading state.\r\n */\r\nlet counter = 0;\r\nexport function generateShimmerKey(prefix: string = 'shimmer'): string {\r\n return `${prefix}-clone-${++counter}`;\r\n}\r\n\r\n/**\r\n * Default fallback dimensions for common elements when their\r\n * measured dimensions are 0px (e.g., empty inputs, images not yet loaded).\r\n */\r\nexport const FALLBACK_DIMENSIONS: Record<string, { width: number; height: number }> = {\r\n INPUT: { width: 200, height: 36 },\r\n BUTTON: { width: 120, height: 36 },\r\n TEXTAREA: { width: 300, height: 80 },\r\n SELECT: { width: 200, height: 36 },\r\n IMG: { width: 100, height: 100 },\r\n H1: { width: 300, height: 36 },\r\n H2: { width: 260, height: 30 },\r\n H3: { width: 220, height: 26 },\r\n H4: { width: 200, height: 22 },\r\n H5: { width: 180, height: 20 },\r\n H6: { width: 160, height: 18 },\r\n P: { width: 250, height: 16 },\r\n SPAN: { width: 100, height: 16 },\r\n};\r\n","import { useLayoutEffect, useState, RefObject, useCallback } from 'react';\r\nimport { ShimmerRect } from './types';\r\nimport { FALLBACK_DIMENSIONS } from './utils';\r\n\r\n/**\r\n * Tags that are always considered \"traceable\" leaf elements\r\n * whose dimensions should be captured for the shimmer overlay.\r\n */\r\nconst TRACEABLE_TAGS = new Set([\r\n // Text\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LI',\r\n 'LABEL', 'TD', 'TH', 'BLOCKQUOTE', 'CODE', 'PRE',\r\n // Media\r\n 'IMG', 'VIDEO', 'SVG', 'CANVAS', 'PICTURE',\r\n // Form\r\n 'INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',\r\n // Misc\r\n 'HR',\r\n]);\r\n\r\n/**\r\n * Determines if an element should be traced.\r\n * Explicit data attributes override automatic detection.\r\n */\r\nfunction isTraceable(el: Element): boolean {\r\n if (el.hasAttribute('data-shimmer-ignore')) return false;\r\n if (el.hasAttribute('data-shimmer')) return true;\r\n if (TRACEABLE_TAGS.has(el.tagName)) return true;\r\n\r\n // Leaf element with visible dimensions → trace it\r\n if (el.children.length === 0) {\r\n const rect = el.getBoundingClientRect();\r\n return rect.width > 0 && rect.height > 0;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Recursively walks the DOM tree and collects all traceable elements.\r\n */\r\nfunction collectTraceableElements(root: Element): Element[] {\r\n const result: Element[] = [];\r\n\r\n function walk(el: Element) {\r\n if (el.hasAttribute('data-shimmer-ignore')) return;\r\n if (el.hasAttribute('data-shimmer-reporter')) return; // Ignore nested reporters, they report their own rects\r\n\r\n if (isTraceable(el)) {\r\n result.push(el);\r\n return; // Don't recurse into traced elements\r\n }\r\n\r\n for (let i = 0; i < el.children.length; i++) {\r\n walk(el.children[i]);\r\n }\r\n }\r\n\r\n for (let i = 0; i < root.children.length; i++) {\r\n walk(root.children[i]);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Measures an element and returns its ShimmerRect relative to the container.\r\n */\r\nfunction measureElement(\r\n el: Element,\r\n containerRect: DOMRect,\r\n globalBorderRadius?: string,\r\n): ShimmerRect | null {\r\n const elRect = el.getBoundingClientRect();\r\n\r\n // If the element is display: none or detached, getBoundingClientRect returns all zeros.\r\n // We must not trace it, otherwise it ends up at the left edge of the screen.\r\n if (elRect.width === 0 && elRect.height === 0 && elRect.left === 0 && elRect.top === 0) {\r\n return null;\r\n }\r\n\r\n const computedStyle = window.getComputedStyle(el);\r\n let borderRadius = globalBorderRadius || computedStyle.borderRadius;\r\n\r\n // If the element has no border radius (common for text tags),\r\n // apply a small default to avoid sharp edges in the shimmer.\r\n const isZero = !borderRadius || borderRadius === 'none' || borderRadius.split(' ').every(v => v === '0' || v === '0px' || v === '0%');\r\n if (isZero) {\r\n borderRadius = '4px';\r\n }\r\n\r\n let width = elRect.width;\r\n let height = elRect.height;\r\n\r\n // Apply fallback dimensions if element has 0 size but is actually visible (e.g. empty inline element)\r\n if (width === 0 || height === 0) {\r\n const fallback = FALLBACK_DIMENSIONS[el.tagName];\r\n if (fallback) {\r\n width = width || fallback.width;\r\n height = height || fallback.height;\r\n }\r\n }\r\n\r\n return {\r\n x: elRect.left - containerRect.left,\r\n y: elRect.top - containerRect.top,\r\n width,\r\n height,\r\n borderRadius,\r\n };\r\n}\r\n\r\n/**\r\n * Performs a full trace of all traceable elements within the container.\r\n *\r\n * @param anchorRef - When provided (Reporter mode), elements are measured\r\n * relative to this element instead of the container. Allows Reporter's\r\n * wrapper to use display:contents without breaking measurement.\r\n */\r\nfunction performTrace(\r\n container: HTMLElement,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const anchor = anchorRef?.current ?? container;\r\n const anchorRect = anchor.getBoundingClientRect();\r\n const elements = collectTraceableElements(container);\r\n\r\n return elements\r\n .map((el) => measureElement(el, anchorRect, globalBorderRadius))\r\n .filter((r): r is ShimmerRect => r !== null && r.width > 0 && r.height > 0);\r\n}\r\n\r\n/**\r\n * Hook that traces all visible leaf DOM elements within a container\r\n * and returns their measured ShimmerRects.\r\n *\r\n * Uses ResizeObserver to re-trace on container resize.\r\n *\r\n * @param anchorRef - When set, rects are relative to this element (Master).\r\n * Used by Reporter so its display:contents wrapper doesn't break measurement.\r\n */\r\nexport function useTrace(\r\n containerRef: RefObject<HTMLElement | null>,\r\n loading: boolean,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const [rects, setRects] = useState<ShimmerRect[]>([]);\r\n\r\n const trace = useCallback(() => {\r\n if (!containerRef.current) return;\r\n const traced = performTrace(containerRef.current, globalBorderRadius, anchorRef);\r\n setRects(traced);\r\n }, [containerRef, globalBorderRadius, anchorRef]);\r\n\r\n useLayoutEffect(() => {\r\n if (!loading || !containerRef.current) {\r\n setRects([]);\r\n return;\r\n }\r\n\r\n // Initial trace\r\n trace();\r\n\r\n // Re-trace on resize\r\n const observer = new ResizeObserver(() => {\r\n trace();\r\n });\r\n observer.observe(containerRef.current);\r\n\r\n return () => observer.disconnect();\r\n }, [loading, trace]);\r\n\r\n return rects;\r\n}\r\n","const SHIMMER_STYLES_ID = 'shimmer-trace-styles';\r\n\r\nconst CSS = `\r\n@keyframes shimmer-wave {\r\n 0% { transform: translateX(-100%); }\r\n 100% { transform: translateX(100%); }\r\n}\r\n\r\n@keyframes shimmer-pulse {\r\n 0%, 100% { opacity: 0.4; }\r\n 50% { opacity: 1; }\r\n}\r\n\r\n@keyframes shimmer-shine {\r\n 0% { transform: translateX(-150%) skewX(-20deg); }\r\n 100% { transform: translateX(150%) skewX(-20deg); }\r\n}\r\n\r\n@keyframes shimmer-glow {\r\n 0%, 100% { filter: brightness(1); }\r\n 50% { filter: brightness(1.35); }\r\n}\r\n\r\n@keyframes shimmer-gradient {\r\n 0% { background-position: 0% 50%; }\r\n 50% { background-position: 100% 50%; }\r\n 100% { background-position: 0% 50%; }\r\n}\r\n\r\n/* preserveBackground mode: hide text + media but keep container styles */\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,td,th,blockquote,code,pre,strong,em,small) {\r\n color: transparent !important;\r\n text-shadow: none !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(img,video,svg,canvas,picture) {\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(input,textarea,select,button) {\r\n color: transparent !important;\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] {\r\n pointer-events: none !important;\r\n user-select: none !important;\r\n}\r\n`;\r\n\r\n/**\r\n * Injects the shimmer keyframe animations into the document head.\r\n * Safe to call multiple times — only injects once.\r\n */\r\nexport function injectStyles(): void {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById(SHIMMER_STYLES_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = SHIMMER_STYLES_ID;\r\n style.textContent = CSS;\r\n document.head.appendChild(style);\r\n}\r\n","import React, { useRef, useCallback, useState, useId, useMemo } from \"react\";\r\nimport { ShimmerProps, ShimmerRect, DEFAULTS } from \"./types\";\r\nimport { ShimmerContext, useShimmerContext } from \"./ShimmerContext\";\r\nimport { ShimmerOverlay } from \"./ShimmerOverlay\";\r\nimport { useTrace } from \"./useTrace\";\r\nimport { injectStyles } from \"./styles\";\r\nimport { generateShimmerKey } from \"./utils\";\r\n\r\n/**\r\n * The main Shimmer component.\r\n *\r\n * Auto-detects **Master** (no parent Shimmer) vs **Reporter** (nested).\r\n * - Master: renders children hidden, traces DOM, paints overlay.\r\n * - Reporter: measures own rects, reports to parent Master.\r\n *\r\n * ### Skeleton shape via `dummyData`\r\n *\r\n * Pass `dummyData` so children render with realistic data while loading.\r\n * No render-prop, no manual `data || fallback` in JSX.\r\n *\r\n * ```tsx\r\n * const userTemplate = { name: 'Loading...', role: '...', avatar: '' };\r\n *\r\n * <Shimmer loading={loading} dummyData={{ user: userTemplate }}>\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * ### List mode (`dummyLength`)\r\n *\r\n * Combined with `dummyData`, clones the first child N times with\r\n * template props merged in:\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyLength={5}\r\n * dummyData={{ fruit: { name: 'xxxxx', price: '$0.00' } }}\r\n * >\r\n * <FruitCard fruit={undefined as any} />\r\n * </Shimmer>\r\n * ```\r\n */\r\nexport function Shimmer({\r\n\tloading = false,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tstopPropagation = false,\r\n\tanimation,\r\n\tbaseColor,\r\n\thighlightColor,\r\n\tspeed,\r\n\tborderRadius,\r\n\tpreserveBackground,\r\n\tclassName,\r\n\tstyle,\r\n}: ShimmerProps) {\r\n\tconst parentContext = useShimmerContext();\r\n\tconst isMaster = !parentContext || stopPropagation;\r\n\tconst id = useId();\r\n\r\n\tconst config = useMemo(\r\n\t\t() => ({\r\n\t\t\tanimation:\r\n\t\t\t\tanimation ?? parentContext?.config.animation ?? DEFAULTS.animation,\r\n\t\t\tbaseColor:\r\n\t\t\t\tbaseColor ?? parentContext?.config.baseColor ?? DEFAULTS.baseColor,\r\n\t\t\thighlightColor:\r\n\t\t\t\thighlightColor ??\r\n\t\t\t\tparentContext?.config.highlightColor ??\r\n\t\t\t\tDEFAULTS.highlightColor,\r\n\t\t\tspeed: speed ?? parentContext?.config.speed ?? DEFAULTS.speed,\r\n\t\t\tborderRadius:\r\n\t\t\t\tborderRadius ??\r\n\t\t\t\tparentContext?.config.borderRadius ??\r\n\t\t\t\tDEFAULTS.borderRadius,\r\n\t\t\tpreserveBackground:\r\n\t\t\t\tpreserveBackground ??\r\n\t\t\t\tparentContext?.config.preserveBackground ??\r\n\t\t\t\tDEFAULTS.preserveBackground,\r\n\t\t}),\r\n\t\t[\r\n\t\t\tanimation,\r\n\t\t\tbaseColor,\r\n\t\t\thighlightColor,\r\n\t\t\tspeed,\r\n\t\t\tborderRadius,\r\n\t\t\tpreserveBackground,\r\n\t\t\tparentContext?.config,\r\n\t\t],\r\n\t);\r\n\r\n\tif (isMaster) {\r\n\t\treturn (\r\n\t\t\t<MasterShimmer\r\n\t\t\t\tid={id}\r\n\t\t\t\tloading={loading}\r\n\t\t\t\tconfig={config}\r\n\t\t\t\tdummyLength={dummyLength}\r\n\t\t\t\tdummyData={dummyData}\r\n\t\t\t\tas={as}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={style}\r\n\t\t\t>\r\n\t\t\t\t{children}\r\n\t\t\t</MasterShimmer>\r\n\t\t);\r\n\t}\r\n\r\n\treturn (\r\n\t\t<ReporterShimmer\r\n\t\t\tid={id}\r\n\t\t\tparentContext={parentContext!}\r\n\t\t\tconfig={config}\r\n\t\t\tdummyLength={dummyLength}\r\n\t\t\tdummyData={dummyData}\r\n\t\t\tas={as}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</ReporterShimmer>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Master ─────────────────── */\r\n\r\ninterface MasterShimmerProps {\r\n\tid: string;\r\n\tloading: boolean;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\nfunction MasterShimmer({\r\n\tid,\r\n\tloading,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tclassName,\r\n\tstyle,\r\n}: MasterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst [reporterRects, setReporterRects] = useState<\r\n\t\tRecord<string, ShimmerRect[]>\r\n\t>({});\r\n\r\n\tconst register = useCallback((rid: string, rects: ShimmerRect[]) => {\r\n\t\tsetReporterRects((prev) => ({ ...prev, [rid]: rects }));\r\n\t}, []);\r\n\r\n\tconst unregister = useCallback((rid: string) => {\r\n\t\tsetReporterRects((prev) => {\r\n\t\t\tconst next = { ...prev };\r\n\t\t\tdelete next[rid];\r\n\t\t\treturn next;\r\n\t\t});\r\n\t}, []);\r\n\r\n\tReact.useEffect(() => {\r\n\t\tinjectStyles();\r\n\t}, []);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tloading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t);\r\n\r\n\tconst allRects = useMemo(() => {\r\n\t\tconst reported = Object.values(reporterRects).flat();\r\n\t\treturn [...tracedRects, ...reported];\r\n\t}, [tracedRects, reporterRects]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\tconst contextValue = useMemo(\r\n\t\t() => ({\r\n\t\t\tregister,\r\n\t\t\tunregister,\r\n\t\t\tmasterRef: containerRef,\r\n\t\t\tloading,\r\n\t\t\tconfig,\r\n\t\t}),\r\n\t\t[register, unregister, loading, config],\r\n\t);\r\n\r\n\treturn (\r\n\t\t<ShimmerContext.Provider value={contextValue}>\r\n\t\t\t<div\r\n\t\t\t\tref={containerRef}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={{\r\n\t\t\t\t\tposition: \"relative\",\r\n\t\t\t\t\tvisibility:\r\n\t\t\t\t\t\tloading && !config.preserveBackground ? \"hidden\" : undefined,\r\n\t\t\t\t\t...style,\r\n\t\t\t\t}}\r\n\t\t\t\taria-hidden={loading || undefined}\r\n\t\t\t\tdata-shimmer-master\r\n\t\t\t\tdata-shimmer-preserve-bg={\r\n\t\t\t\t\tloading && config.preserveBackground ? \"true\" : undefined\r\n\t\t\t\t}\r\n\t\t\t>\r\n\t\t\t\t{renderedChildren}\r\n\r\n\t\t\t\t{loading && (\r\n\t\t\t\t\t<ShimmerOverlay\r\n\t\t\t\t\t\trects={allRects}\r\n\t\t\t\t\t\tanimation={config.animation}\r\n\t\t\t\t\t\tbaseColor={config.baseColor}\r\n\t\t\t\t\t\thighlightColor={config.highlightColor}\r\n\t\t\t\t\t\tspeed={config.speed}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t</div>\r\n\t\t</ShimmerContext.Provider>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Reporter ─────────────────── */\r\n\r\ninterface ReporterShimmerProps {\r\n\tid: string;\r\n\tparentContext: NonNullable<ReturnType<typeof useShimmerContext>>;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n}\r\n\r\nfunction ReporterShimmer({\r\n\tid,\r\n\tparentContext,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n}: ReporterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tparentContext.loading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t\tparentContext.masterRef,\r\n\t);\r\n\r\n\tReact.useLayoutEffect(() => {\r\n\t\tif (!parentContext.loading || tracedRects.length === 0) {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tparentContext.register(id, tracedRects);\r\n\t\treturn () => {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t};\r\n\t}, [tracedRects, parentContext, id]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading: parentContext.loading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<div\r\n\t\t\tref={containerRef}\r\n\t\t\tdata-shimmer-reporter\r\n\t\t\tstyle={{ display: \"contents\" }}\r\n\t\t>\r\n\t\t\t{renderedChildren}\r\n\t\t</div>\r\n\t);\r\n}\r\n\r\n/* ─────────────── Skeleton Children ─────────────── */\r\n\r\ninterface UseSkeletonChildrenParams {\r\n\tloading: boolean;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tid: string;\r\n}\r\n\r\n/**\r\n * Build the rendered children tree.\r\n *\r\n * Priority during `loading=true`:\r\n * 1. `as` set → render `dummyLength` (or 1) instances of `<as {...dummyData} />`.\r\n * Children ignored. Cold-start safe.\r\n * 2. `dummyData` set + children present → clone each child merging\r\n * dummyData over its props. If `dummyLength` set, clone first\r\n * templated child N times.\r\n * 3. None → pass children through (e.g. `useIsShimmering` flow).\r\n *\r\n * `loading=false` → children untouched.\r\n */\r\nfunction useSkeletonChildren({\r\n\tloading,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tid,\r\n}: UseSkeletonChildrenParams): React.ReactNode {\r\n\tif (!loading) return children;\r\n\r\n\tif (as) {\r\n\t\tconst count = dummyLength && dummyLength > 0 ? dummyLength : 1;\r\n\t\tconst Component = as;\r\n\t\treturn Array.from({ length: count }, (_, i) => (\r\n\t\t\t<Component\r\n\t\t\t\t{...(dummyData || {})}\r\n\t\t\t\tkey={generateShimmerKey(`${id}-as-${i}`)}\r\n\t\t\t/>\r\n\t\t));\r\n\t}\r\n\r\n\tconst childArray = React.Children.toArray(children);\r\n\r\n\tconst templated = childArray.map((c, i) => {\r\n\t\tif (!React.isValidElement(c)) return c;\r\n\t\tconst key = generateShimmerKey(`${id}-tpl-${i}`);\r\n\t\tconst props = dummyData ? { ...dummyData, key } : { key };\r\n\t\treturn React.cloneElement(c as React.ReactElement, props as any);\r\n\t});\r\n\r\n\tif (dummyLength && dummyLength > 0) {\r\n\t\tconst first = templated.find((c) => React.isValidElement(c)) as\r\n\t\t\t| React.ReactElement\r\n\t\t\t| undefined;\r\n\t\tif (!first) return null;\r\n\t\treturn Array.from({ length: dummyLength }, (_, i) =>\r\n\t\t\tReact.cloneElement(first, {\r\n\t\t\t\tkey: generateShimmerKey(`${id}-clone-${i}`),\r\n\t\t\t} as any),\r\n\t\t);\r\n\t}\r\n\r\n\treturn templated;\r\n}\r\n","import React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { ShimmerConfig, ShimmerProps, DEFAULTS } from './types';\r\n\r\n/**\r\n * Factory function to create a pre-configured Shimmer component.\r\n * Avoids \"Provider Hell\" by baking config into the returned component.\r\n *\r\n * All config properties are optional — defaults are used for anything\r\n * not specified.\r\n *\r\n * @example\r\n * ```tsx\r\n * const AppShimmer = createShimmer({\r\n * animation: 'pulse',\r\n * baseColor: '#1a1a2e',\r\n * highlightColor: '#16213e',\r\n * speed: 2,\r\n * });\r\n *\r\n * <AppShimmer loading={isLoading}>\r\n * <MyComponent />\r\n * </AppShimmer>\r\n * ```\r\n */\r\nexport function createShimmer(config: ShimmerConfig = {}) {\r\n const mergedConfig: Required<ShimmerConfig> = {\r\n animation: config.animation ?? DEFAULTS.animation,\r\n baseColor: config.baseColor ?? DEFAULTS.baseColor,\r\n highlightColor: config.highlightColor ?? DEFAULTS.highlightColor,\r\n speed: config.speed ?? DEFAULTS.speed,\r\n borderRadius: config.borderRadius ?? DEFAULTS.borderRadius,\r\n preserveBackground: config.preserveBackground ?? DEFAULTS.preserveBackground,\r\n };\r\n\r\n function ConfiguredShimmer(props: Omit<ShimmerProps, keyof ShimmerConfig> & Partial<ShimmerConfig>) {\r\n return (\r\n <Shimmer\r\n {...mergedConfig}\r\n {...props}\r\n />\r\n );\r\n }\r\n\r\n // Removed ConfiguredShimmer.displayName\r\n return ConfiguredShimmer;\r\n}\r\n","import React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { IsShimmeringContext } from './ShimmerContext';\r\nimport { ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerSuspenseProps extends ShimmerConfig {\r\n children: React.ReactNode;\r\n /**\r\n * Explicit skeleton template. Rendered hidden and traced for shimmer shape.\r\n *\r\n * Preferred — pass the same component with no data props:\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * If omitted, falls back to Option B: children are re-rendered with\r\n * `useIsShimmering()=true` so they can return an empty shape themselves.\r\n */\r\n template?: React.ReactNode;\r\n}\r\n\r\n/**\r\n * Suspense boundary that automatically shows a shimmer skeleton while\r\n * children are suspended (e.g. useSuspenseQuery, use(promise), etc).\r\n *\r\n * **Option A — explicit template (preferred):**\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * **Option B — useIsShimmering hook (no template):**\r\n * ```tsx\r\n * function UserCard() {\r\n * const isShimmering = useIsShimmering();\r\n * const data = isShimmering ? null : useSuspenseQuery(...);\r\n * return <div><h3>{data?.name}</h3></div>;\r\n * }\r\n *\r\n * <ShimmerSuspense>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n * Components must use `useIsShimmering()` to skip data fetching in shimmer mode,\r\n * otherwise they will also suspend inside the fallback (causing an empty skeleton).\r\n */\r\nexport function ShimmerSuspense({\r\n children,\r\n template,\r\n ...shimmerConfig\r\n}: ShimmerSuspenseProps) {\r\n const skeletonContent =\r\n template !== undefined ? (\r\n template\r\n ) : (\r\n <IsShimmeringContext.Provider value={true}>\r\n {children}\r\n </IsShimmeringContext.Provider>\r\n );\r\n\r\n return (\r\n <React.Suspense\r\n fallback={\r\n <Shimmer loading={true} {...shimmerConfig}>\r\n {skeletonContent}\r\n </Shimmer>\r\n }\r\n >\r\n {children}\r\n </React.Suspense>\r\n );\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/ShimmerContext.tsx","../src/ShimmerOverlay.tsx","../src/utils.ts","../src/useTrace.ts","../src/styles.ts","../src/Shimmer.tsx","../src/createShimmer.tsx","../src/ShimmerSuspense.tsx"],"names":["React","jsx","useState","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { ReactNode } from 'react';\r\n\r\n/**\r\n * Represents a measured rectangle of a traced DOM element,\r\n * positioned relative to the Master Shimmer container.\r\n */\r\nexport interface ShimmerRect {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n borderRadius: string;\r\n}\r\n\r\n/** Available animation types for the shimmer effect. */\r\nexport type AnimationType =\r\n | 'wave'\r\n | 'pulse'\r\n | 'shine'\r\n | 'glow'\r\n | 'gradient';\r\n\r\n/** Configuration options for the shimmer effect (all optional). */\r\nexport interface ShimmerConfig {\r\n /** Animation style. Defaults to 'wave'. */\r\n animation?: AnimationType;\r\n /** Base color of the shimmer blocks. Defaults to '#e0e0e0'. */\r\n baseColor?: string;\r\n /** Highlight color of the shimmer animation. Defaults to '#f5f5f5'. */\r\n highlightColor?: string;\r\n /** Animation duration in seconds. Defaults to 1.5. */\r\n speed?: number;\r\n /** Global border-radius override. If omitted, auto-detected from each element (defaults to 4px if detection is 0px). */\r\n borderRadius?: string;\r\n /**\r\n * Keep container backgrounds, borders, and padding visible while loading.\r\n * When `true` (default), only text and media leaves are hidden via\r\n * `color:transparent` / `opacity:0` so card backgrounds, borders, and\r\n * spacing remain visible underneath the shimmer overlay.\r\n *\r\n * Set `false` for legacy behavior (`visibility:hidden` on whole tree).\r\n */\r\n preserveBackground?: boolean;\r\n}\r\n\r\n/** Props for the Shimmer component. */\r\nexport interface ShimmerProps extends ShimmerConfig {\r\n /** Whether the loading state is active. */\r\n loading?: boolean;\r\n /** The children to trace and render shimmer over. */\r\n children: ReactNode;\r\n /**\r\n * Number of placeholder clones to generate for list-like loading states.\r\n *\r\n * When `loading=true` and `dummyLength` is set, Shimmer grabs the first\r\n * available child (or a cached template from the last loaded render) and\r\n * clones it `dummyLength` times to produce skeleton placeholders.\r\n *\r\n * When `loading=false`, children are rendered as-is.\r\n */\r\n dummyLength?: number;\r\n /**\r\n * Props injected into each child element while `loading=true` so the\r\n * skeleton renders with realistic shape without requiring real data.\r\n *\r\n * Example:\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyData={{ user: { name: 'Loading...', role: '...', avatar: '' } }}\r\n * >\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * While loading, each direct child is cloned with these props merged on top\r\n * of its own props. Ignored when `loading=false`.\r\n */\r\n dummyData?: Record<string, any>;\r\n /**\r\n * Component used to auto-generate skeleton elements while `loading=true`.\r\n *\r\n * When set, Shimmer ignores `children` during loading and renders\r\n * `dummyLength` (defaults to 1) instances of `<as {...dummyData} />`\r\n * to derive shape. Real children render once `loading=false`.\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * as={MovieCard}\r\n * dummyData={{ movie: movieTemplate }}\r\n * dummyLength={10}\r\n * >\r\n * {movies.map((m) => <MovieCard movie={m} key={m.id} />)}\r\n * </Shimmer>\r\n * ```\r\n */\r\n as?: React.ComponentType<any>;\r\n /** Force this Shimmer to be a Master renderer even if nested inside another Shimmer. */\r\n stopPropagation?: boolean;\r\n /**\r\n * className applied to the Master container div.\r\n * Use to control layout (e.g. display:flex) without losing position:relative.\r\n */\r\n className?: string;\r\n /**\r\n * Inline styles merged into the Master container div.\r\n * position:relative is always applied; everything else is overridable.\r\n */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/** Default configuration values. */\r\nexport const DEFAULTS: Required<ShimmerConfig> = {\r\n animation: 'wave',\r\n baseColor: '#e0e0e0',\r\n highlightColor: '#f5f5f5',\r\n speed: 1.5,\r\n borderRadius: '',\r\n preserveBackground: true,\r\n};\r\n","\"use client\";\r\n\r\nimport { createContext, useContext, RefObject } from \"react\";\r\nimport { ShimmerRect, ShimmerConfig } from \"./types\";\r\n\r\nexport interface ShimmerContextValue {\r\n\tregister: (id: string, rects: ShimmerRect[]) => void;\r\n\tunregister: (id: string) => void;\r\n\t/** Ref object (not .current) so Reporters always read a fresh value. */\r\n\tmasterRef: RefObject<HTMLElement | null>;\r\n\tloading: boolean;\r\n\tconfig: Required<ShimmerConfig>;\r\n}\r\n\r\nexport const ShimmerContext = createContext<ShimmerContextValue | null>(null);\r\n\r\nexport function useShimmerContext(): ShimmerContextValue | null {\r\n\treturn useContext(ShimmerContext);\r\n}\r\n\r\n/**\r\n * True when rendered inside a ShimmerSuspense fallback (Option B).\r\n * Components use this to skip data fetching and return an empty shape.\r\n */\r\nexport const IsShimmeringContext = createContext<boolean>(false);\r\n\r\nexport function useIsShimmering(): boolean {\r\n\treturn useContext(IsShimmeringContext);\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { ShimmerRect, AnimationType } from './types';\r\n\r\ninterface ShimmerOverlayProps {\r\n rects: ShimmerRect[];\r\n animation: AnimationType;\r\n baseColor: string;\r\n highlightColor: string;\r\n speed: number;\r\n}\r\n\r\n/**\r\n * Returns animation-specific inline styles for each shimmer block.\r\n * For sweep-style animations (wave, shine), the colored gradient is rendered\r\n * as a child layer so the sweep can extend across the container in sync.\r\n */\r\nfunction getBlockStyles(\r\n animation: AnimationType,\r\n baseColor: string,\r\n highlightColor: string,\r\n speed: number,\r\n rect: ShimmerRect,\r\n): React.CSSProperties {\r\n const base: React.CSSProperties = {\r\n position: 'absolute',\r\n top: rect.y,\r\n left: rect.x,\r\n width: rect.width,\r\n height: rect.height,\r\n borderRadius: rect.borderRadius,\r\n overflow: 'hidden',\r\n };\r\n\r\n switch (animation) {\r\n case 'wave':\r\n case 'shine':\r\n return { ...base, background: baseColor };\r\n case 'pulse':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-pulse ${speed}s ease-in-out infinite`,\r\n };\r\n case 'glow':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-glow ${speed}s ease-in-out infinite`,\r\n };\r\n case 'gradient':\r\n return {\r\n ...base,\r\n backgroundImage: `linear-gradient(90deg, ${baseColor}, ${highlightColor}, ${baseColor})`,\r\n backgroundSize: '200% 100%',\r\n animation: `shimmer-gradient ${speed * 1.5}s ease-in-out infinite`,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Sweeping shine layer used by `wave` and `shine` animations.\r\n * Spans the full container width so the highlight sweeps in sync across all blocks.\r\n */\r\nconst SweepLayer: React.FC<{\r\n rect: ShimmerRect;\r\n highlightColor: string;\r\n speed: number;\r\n containerWidth: number;\r\n variant: 'wave' | 'shine';\r\n}> = ({ rect, highlightColor, speed, containerWidth, variant }) => {\r\n const isShine = variant === 'shine';\r\n return (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: -rect.x,\r\n width: containerWidth > 0 ? containerWidth : '100vw',\r\n height: '100%',\r\n background: isShine\r\n ? `linear-gradient(115deg, transparent 30%, ${highlightColor} 50%, transparent 70%)`\r\n : `linear-gradient(90deg, transparent 0%, ${highlightColor} 50%, transparent 100%)`,\r\n animation: `${isShine ? 'shimmer-shine' : 'shimmer-wave'} ${speed}s ease-in-out infinite`,\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * The overlay component rendered by the Master Shimmer.\r\n *\r\n * Renders one absolutely-positioned div per traced rect. Sweep-style\r\n * animations (`wave`, `shine`) get an additional gradient layer that spans\r\n * the container so the highlight passes across all blocks in sync.\r\n */\r\nexport const ShimmerOverlay: React.FC<ShimmerOverlayProps> = ({\r\n rects,\r\n animation,\r\n baseColor,\r\n highlightColor,\r\n speed,\r\n}) => {\r\n const overlayRef = React.useRef<HTMLDivElement>(null);\r\n const [containerWidth, setContainerWidth] = React.useState(0);\r\n\r\n React.useLayoutEffect(() => {\r\n if (!overlayRef.current?.parentElement) return;\r\n setContainerWidth(overlayRef.current.parentElement.offsetWidth);\r\n }, [rects]);\r\n\r\n if (rects.length === 0) return null;\r\n\r\n const isSweep = animation === 'wave' || animation === 'shine';\r\n\r\n return (\r\n <div\r\n ref={overlayRef}\r\n role=\"status\"\r\n aria-busy=\"true\"\r\n aria-label=\"Loading content\"\r\n data-shimmer-ignore=\"true\"\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n zIndex: 1,\r\n pointerEvents: 'none',\r\n visibility: 'visible',\r\n }}\r\n >\r\n {rects.map((rect, i) => (\r\n <div\r\n key={i}\r\n style={getBlockStyles(animation, baseColor, highlightColor, speed, rect)}\r\n >\r\n {isSweep && (\r\n <SweepLayer\r\n rect={rect}\r\n highlightColor={highlightColor}\r\n speed={speed}\r\n containerWidth={containerWidth}\r\n variant={animation as 'wave' | 'shine'}\r\n />\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * Generates a deterministic key for cloned elements.\r\n *\r\n * Prefix already includes the parent Shimmer's `useId()` plus a positional\r\n * index from the caller, so it is unique per render slot and stable across\r\n * SSR + client hydration. No module-scope counter — that caused hydration\r\n * mismatches and forced React to remount cloned children every render.\r\n */\r\nexport function generateShimmerKey(prefix: string = 'shimmer'): string {\r\n return prefix;\r\n}\r\n\r\n/**\r\n * Default fallback dimensions for common elements when their\r\n * measured dimensions are 0px (e.g., empty inputs, images not yet loaded).\r\n */\r\nexport const FALLBACK_DIMENSIONS: Record<string, { width: number; height: number }> = {\r\n INPUT: { width: 200, height: 36 },\r\n BUTTON: { width: 120, height: 36 },\r\n TEXTAREA: { width: 300, height: 80 },\r\n SELECT: { width: 200, height: 36 },\r\n IMG: { width: 100, height: 100 },\r\n H1: { width: 300, height: 36 },\r\n H2: { width: 260, height: 30 },\r\n H3: { width: 220, height: 26 },\r\n H4: { width: 200, height: 22 },\r\n H5: { width: 180, height: 20 },\r\n H6: { width: 160, height: 18 },\r\n P: { width: 250, height: 16 },\r\n SPAN: { width: 100, height: 16 },\r\n};\r\n","'use client';\r\n\r\nimport { useLayoutEffect, useState, RefObject, useCallback } from 'react';\r\nimport { ShimmerRect } from './types';\r\nimport { FALLBACK_DIMENSIONS } from './utils';\r\n\r\n/**\r\n * Tags that are always considered \"traceable\" leaf elements\r\n * whose dimensions should be captured for the shimmer overlay.\r\n */\r\nconst TRACEABLE_TAGS = new Set([\r\n // Text\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LI',\r\n 'LABEL', 'TD', 'TH', 'BLOCKQUOTE', 'CODE', 'PRE',\r\n // Media\r\n 'IMG', 'VIDEO', 'SVG', 'CANVAS', 'PICTURE',\r\n // Form\r\n 'INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',\r\n // Misc\r\n 'HR',\r\n]);\r\n\r\n/**\r\n * Determines if an element should be traced.\r\n * Explicit data attributes override automatic detection.\r\n */\r\nfunction isTraceable(el: Element): boolean {\r\n if (el.hasAttribute('data-shimmer-ignore')) return false;\r\n if (el.hasAttribute('data-shimmer')) return true;\r\n if (TRACEABLE_TAGS.has(el.tagName)) return true;\r\n\r\n // Leaf element with visible dimensions → trace it\r\n if (el.children.length === 0) {\r\n const rect = el.getBoundingClientRect();\r\n return rect.width > 0 && rect.height > 0;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Detects elements whose coordinate space cannot follow the Master\r\n * container during scroll. `position: fixed` and `position: sticky`\r\n * both live in a different scroll context (viewport / nearest scroll\r\n * container) than the Master, so any container-relative rect we compute\r\n * for them becomes stale on the first scroll.\r\n *\r\n * Returning `true` here causes the entire subtree under `el` to be\r\n * skipped, since descendants of a fixed/sticky element inherit the same\r\n * broken coordinate space.\r\n */\r\nfunction isViewportLocked(el: Element): boolean {\r\n const pos = window.getComputedStyle(el).position;\r\n return pos === 'fixed' || pos === 'sticky';\r\n}\r\n\r\n/**\r\n * Tracks Master containers we've already warned about, so the\r\n * console.warn fires once per container instead of on every resize-driven\r\n * re-trace. WeakSet keeps the dedupe noise-free across container churn —\r\n * a fresh Master gets one warning, period.\r\n */\r\nconst warnedContainers = new WeakSet<Element>();\r\n\r\ninterface CollectResult {\r\n traced: Element[];\r\n skippedFixed: number;\r\n}\r\n\r\n/**\r\n * Recursively walks the DOM tree and collects all traceable elements.\r\n *\r\n * Also reports how many elements were silently skipped because they used\r\n * `position: fixed` / `position: sticky`. Users can override this skip\r\n * by adding `data-shimmer` to the element, but the resulting overlay\r\n * block will drift on scroll — that's their choice to make.\r\n */\r\nfunction collectTraceableElements(root: Element): CollectResult {\r\n const traced: Element[] = [];\r\n let skippedFixed = 0;\r\n\r\n function walk(el: Element) {\r\n if (el.hasAttribute('data-shimmer-ignore')) return;\r\n if (el.hasAttribute('data-shimmer-reporter')) return; // Ignore nested reporters, they report their own rects\r\n\r\n // `data-shimmer` is an explicit opt-in — trust the user and trace.\r\n // Without it, fixed/sticky elements are skipped entirely (including\r\n // their descendants, which share the broken coordinate space).\r\n if (!el.hasAttribute('data-shimmer') && isViewportLocked(el)) {\r\n skippedFixed += 1;\r\n return;\r\n }\r\n\r\n if (isTraceable(el)) {\r\n traced.push(el);\r\n return; // Don't recurse into traced elements\r\n }\r\n\r\n for (let i = 0; i < el.children.length; i++) {\r\n walk(el.children[i]);\r\n }\r\n }\r\n\r\n for (let i = 0; i < root.children.length; i++) {\r\n walk(root.children[i]);\r\n }\r\n\r\n return { traced, skippedFixed };\r\n}\r\n\r\n/**\r\n * Measures an element and returns its ShimmerRect relative to the container.\r\n */\r\nfunction measureElement(\r\n el: Element,\r\n containerRect: DOMRect,\r\n globalBorderRadius?: string,\r\n): ShimmerRect | null {\r\n const elRect = el.getBoundingClientRect();\r\n\r\n // If the element is display: none or detached, getBoundingClientRect returns all zeros.\r\n // We must not trace it, otherwise it ends up at the left edge of the screen.\r\n if (elRect.width === 0 && elRect.height === 0 && elRect.left === 0 && elRect.top === 0) {\r\n return null;\r\n }\r\n\r\n const computedStyle = window.getComputedStyle(el);\r\n let borderRadius = globalBorderRadius || computedStyle.borderRadius;\r\n\r\n // If the element has no border radius (common for text tags),\r\n // apply a small default to avoid sharp edges in the shimmer.\r\n const isZero = !borderRadius || borderRadius === 'none' || borderRadius.split(' ').every(v => v === '0' || v === '0px' || v === '0%');\r\n if (isZero) {\r\n borderRadius = '4px';\r\n }\r\n\r\n let width = elRect.width;\r\n let height = elRect.height;\r\n\r\n // Apply fallback dimensions if element has 0 size but is actually visible (e.g. empty inline element)\r\n if (width === 0 || height === 0) {\r\n const fallback = FALLBACK_DIMENSIONS[el.tagName];\r\n if (fallback) {\r\n width = width || fallback.width;\r\n height = height || fallback.height;\r\n }\r\n }\r\n\r\n return {\r\n x: elRect.left - containerRect.left,\r\n y: elRect.top - containerRect.top,\r\n width,\r\n height,\r\n borderRadius,\r\n };\r\n}\r\n\r\n/**\r\n * Performs a full trace of all traceable elements within the container.\r\n *\r\n * @param anchorRef - When provided (Reporter mode), elements are measured\r\n * relative to this element instead of the container. Allows Reporter's\r\n * wrapper to use display:contents without breaking measurement.\r\n */\r\nfunction performTrace(\r\n container: HTMLElement,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const anchor = anchorRef?.current ?? container;\r\n const anchorRect = anchor.getBoundingClientRect();\r\n const { traced, skippedFixed } = collectTraceableElements(container);\r\n\r\n if (skippedFixed > 0 && !warnedContainers.has(container)) {\r\n warnedContainers.add(container);\r\n // eslint-disable-next-line no-console\r\n console.warn(\r\n `[shimmer-trace] Skipped ${skippedFixed} element(s) with ` +\r\n `position:fixed or position:sticky. Their coordinate space ` +\r\n `cannot follow the Master container during scroll, so the overlay ` +\r\n `block would drift. Render a nested <Shimmer> inside the fixed/sticky ` +\r\n `element if you need a skeleton there, or add data-shimmer to opt in ` +\r\n `(positioning may still drift on scroll).`,\r\n );\r\n }\r\n\r\n return traced\r\n .map((el) => measureElement(el, anchorRect, globalBorderRadius))\r\n .filter((r): r is ShimmerRect => r !== null && r.width > 0 && r.height > 0);\r\n}\r\n\r\n/**\r\n * Hook that traces all visible leaf DOM elements within a container\r\n * and returns their measured ShimmerRects.\r\n *\r\n * Uses ResizeObserver to re-trace on container resize.\r\n *\r\n * @param anchorRef - When set, rects are relative to this element (Master).\r\n * Used by Reporter so its display:contents wrapper doesn't break measurement.\r\n */\r\nexport function useTrace(\r\n containerRef: RefObject<HTMLElement | null>,\r\n loading: boolean,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const [rects, setRects] = useState<ShimmerRect[]>([]);\r\n\r\n const trace = useCallback(() => {\r\n if (!containerRef.current) return;\r\n const traced = performTrace(containerRef.current, globalBorderRadius, anchorRef);\r\n setRects(traced);\r\n }, [containerRef, globalBorderRadius, anchorRef]);\r\n\r\n useLayoutEffect(() => {\r\n if (!loading || !containerRef.current) {\r\n setRects([]);\r\n return;\r\n }\r\n\r\n // Initial trace\r\n trace();\r\n\r\n // Re-trace on resize\r\n const observer = new ResizeObserver(() => {\r\n trace();\r\n });\r\n observer.observe(containerRef.current);\r\n\r\n return () => observer.disconnect();\r\n }, [loading, trace]);\r\n\r\n return rects;\r\n}\r\n","const SHIMMER_STYLES_ID = 'shimmer-trace-styles';\r\n\r\nconst CSS = `\r\n@keyframes shimmer-wave {\r\n 0% { transform: translateX(-100%); }\r\n 100% { transform: translateX(100%); }\r\n}\r\n\r\n@keyframes shimmer-pulse {\r\n 0%, 100% { opacity: 0.4; }\r\n 50% { opacity: 1; }\r\n}\r\n\r\n@keyframes shimmer-shine {\r\n 0% { transform: translateX(-150%) skewX(-20deg); }\r\n 100% { transform: translateX(150%) skewX(-20deg); }\r\n}\r\n\r\n@keyframes shimmer-glow {\r\n 0%, 100% { filter: brightness(1); }\r\n 50% { filter: brightness(1.35); }\r\n}\r\n\r\n@keyframes shimmer-gradient {\r\n 0% { background-position: 0% 50%; }\r\n 50% { background-position: 100% 50%; }\r\n 100% { background-position: 0% 50%; }\r\n}\r\n\r\n/* preserveBackground mode: hide text + media but keep container styles */\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,td,th,blockquote,code,pre,strong,em,small) {\r\n color: transparent !important;\r\n text-shadow: none !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(img,video,svg,canvas,picture) {\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(input,textarea,select,button) {\r\n color: transparent !important;\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] {\r\n pointer-events: none !important;\r\n user-select: none !important;\r\n}\r\n`;\r\n\r\n/**\r\n * Injects the shimmer keyframe animations into the document head.\r\n * Safe to call multiple times — only injects once.\r\n */\r\nexport function injectStyles(): void {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById(SHIMMER_STYLES_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = SHIMMER_STYLES_ID;\r\n style.textContent = CSS;\r\n document.head.appendChild(style);\r\n}\r\n","'use client';\r\n\r\nimport React, { useRef, useCallback, useState, useId, useMemo, useInsertionEffect } from \"react\";\r\nimport { ShimmerProps, ShimmerRect, DEFAULTS } from \"./types\";\r\nimport { ShimmerContext, useShimmerContext } from \"./ShimmerContext\";\r\nimport { ShimmerOverlay } from \"./ShimmerOverlay\";\r\nimport { useTrace } from \"./useTrace\";\r\nimport { injectStyles } from \"./styles\";\r\nimport { generateShimmerKey } from \"./utils\";\r\n\r\n/**\r\n * The main Shimmer component.\r\n *\r\n * Auto-detects **Master** (no parent Shimmer) vs **Reporter** (nested).\r\n * - Master: renders children hidden, traces DOM, paints overlay.\r\n * - Reporter: measures own rects, reports to parent Master.\r\n *\r\n * ### Skeleton shape via `dummyData`\r\n *\r\n * Pass `dummyData` so children render with realistic data while loading.\r\n * No render-prop, no manual `data || fallback` in JSX.\r\n *\r\n * ```tsx\r\n * const userTemplate = { name: 'Loading...', role: '...', avatar: '' };\r\n *\r\n * <Shimmer loading={loading} dummyData={{ user: userTemplate }}>\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * ### List mode (`dummyLength`)\r\n *\r\n * Combined with `dummyData`, clones the first child N times with\r\n * template props merged in:\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyLength={5}\r\n * dummyData={{ fruit: { name: 'xxxxx', price: '$0.00' } }}\r\n * >\r\n * <FruitCard fruit={undefined as any} />\r\n * </Shimmer>\r\n * ```\r\n */\r\nexport function Shimmer({\r\n\tloading = false,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tstopPropagation = false,\r\n\tanimation,\r\n\tbaseColor,\r\n\thighlightColor,\r\n\tspeed,\r\n\tborderRadius,\r\n\tpreserveBackground,\r\n\tclassName,\r\n\tstyle,\r\n}: ShimmerProps) {\r\n\tconst parentContext = useShimmerContext();\r\n\tconst isMaster = !parentContext || stopPropagation;\r\n\tconst id = useId();\r\n\r\n\tconst config = useMemo(\r\n\t\t() => ({\r\n\t\t\tanimation:\r\n\t\t\t\tanimation ?? parentContext?.config.animation ?? DEFAULTS.animation,\r\n\t\t\tbaseColor:\r\n\t\t\t\tbaseColor ?? parentContext?.config.baseColor ?? DEFAULTS.baseColor,\r\n\t\t\thighlightColor:\r\n\t\t\t\thighlightColor ??\r\n\t\t\t\tparentContext?.config.highlightColor ??\r\n\t\t\t\tDEFAULTS.highlightColor,\r\n\t\t\tspeed: speed ?? parentContext?.config.speed ?? DEFAULTS.speed,\r\n\t\t\tborderRadius:\r\n\t\t\t\tborderRadius ??\r\n\t\t\t\tparentContext?.config.borderRadius ??\r\n\t\t\t\tDEFAULTS.borderRadius,\r\n\t\t\tpreserveBackground:\r\n\t\t\t\tpreserveBackground ??\r\n\t\t\t\tparentContext?.config.preserveBackground ??\r\n\t\t\t\tDEFAULTS.preserveBackground,\r\n\t\t}),\r\n\t\t[\r\n\t\t\tanimation,\r\n\t\t\tbaseColor,\r\n\t\t\thighlightColor,\r\n\t\t\tspeed,\r\n\t\t\tborderRadius,\r\n\t\t\tpreserveBackground,\r\n\t\t\tparentContext?.config,\r\n\t\t],\r\n\t);\r\n\r\n\tif (isMaster) {\r\n\t\treturn (\r\n\t\t\t<MasterShimmer\r\n\t\t\t\tid={id}\r\n\t\t\t\tloading={loading}\r\n\t\t\t\tconfig={config}\r\n\t\t\t\tdummyLength={dummyLength}\r\n\t\t\t\tdummyData={dummyData}\r\n\t\t\t\tas={as}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={style}\r\n\t\t\t>\r\n\t\t\t\t{children}\r\n\t\t\t</MasterShimmer>\r\n\t\t);\r\n\t}\r\n\r\n\treturn (\r\n\t\t<ReporterShimmer\r\n\t\t\tid={id}\r\n\t\t\tparentContext={parentContext!}\r\n\t\t\tconfig={config}\r\n\t\t\tdummyLength={dummyLength}\r\n\t\t\tdummyData={dummyData}\r\n\t\t\tas={as}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</ReporterShimmer>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Master ─────────────────── */\r\n\r\ninterface MasterShimmerProps {\r\n\tid: string;\r\n\tloading: boolean;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\nfunction MasterShimmer({\r\n\tid,\r\n\tloading,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tclassName,\r\n\tstyle,\r\n}: MasterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst [reporterRects, setReporterRects] = useState<\r\n\t\tRecord<string, ShimmerRect[]>\r\n\t>({});\r\n\r\n\tconst register = useCallback((rid: string, rects: ShimmerRect[]) => {\r\n\t\tsetReporterRects((prev) => ({ ...prev, [rid]: rects }));\r\n\t}, []);\r\n\r\n\tconst unregister = useCallback((rid: string) => {\r\n\t\tsetReporterRects((prev) => {\r\n\t\t\tconst next = { ...prev };\r\n\t\t\tdelete next[rid];\r\n\t\t\treturn next;\r\n\t\t});\r\n\t}, []);\r\n\r\n\tuseInsertionEffect(() => {\r\n\t\tinjectStyles();\r\n\t}, []);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tloading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t);\r\n\r\n\tconst allRects = useMemo(() => {\r\n\t\tconst reported = Object.values(reporterRects).flat();\r\n\t\treturn [...tracedRects, ...reported];\r\n\t}, [tracedRects, reporterRects]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\tconst contextValue = useMemo(\r\n\t\t() => ({\r\n\t\t\tregister,\r\n\t\t\tunregister,\r\n\t\t\tmasterRef: containerRef,\r\n\t\t\tloading,\r\n\t\t\tconfig,\r\n\t\t}),\r\n\t\t[register, unregister, loading, config],\r\n\t);\r\n\r\n\treturn (\r\n\t\t<ShimmerContext.Provider value={contextValue}>\r\n\t\t\t<div\r\n\t\t\t\tref={containerRef}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={{\r\n\t\t\t\t\tposition: \"relative\",\r\n\t\t\t\t\tvisibility:\r\n\t\t\t\t\t\tloading && !config.preserveBackground ? \"hidden\" : undefined,\r\n\t\t\t\t\t...style,\r\n\t\t\t\t}}\r\n\t\t\t\taria-hidden={loading || undefined}\r\n\t\t\t\tdata-shimmer-master\r\n\t\t\t\tdata-shimmer-preserve-bg={\r\n\t\t\t\t\tloading && config.preserveBackground ? \"true\" : undefined\r\n\t\t\t\t}\r\n\t\t\t>\r\n\t\t\t\t{renderedChildren}\r\n\r\n\t\t\t\t{loading && (\r\n\t\t\t\t\t<ShimmerOverlay\r\n\t\t\t\t\t\trects={allRects}\r\n\t\t\t\t\t\tanimation={config.animation}\r\n\t\t\t\t\t\tbaseColor={config.baseColor}\r\n\t\t\t\t\t\thighlightColor={config.highlightColor}\r\n\t\t\t\t\t\tspeed={config.speed}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t</div>\r\n\t\t</ShimmerContext.Provider>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Reporter ─────────────────── */\r\n\r\ninterface ReporterShimmerProps {\r\n\tid: string;\r\n\tparentContext: NonNullable<ReturnType<typeof useShimmerContext>>;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n}\r\n\r\nfunction ReporterShimmer({\r\n\tid,\r\n\tparentContext,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n}: ReporterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tparentContext.loading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t\tparentContext.masterRef,\r\n\t);\r\n\r\n\tReact.useLayoutEffect(() => {\r\n\t\tif (!parentContext.loading || tracedRects.length === 0) {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tparentContext.register(id, tracedRects);\r\n\t\treturn () => {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t};\r\n\t}, [tracedRects, parentContext, id]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading: parentContext.loading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<div\r\n\t\t\tref={containerRef}\r\n\t\t\tdata-shimmer-reporter\r\n\t\t\tstyle={{ display: \"contents\" }}\r\n\t\t>\r\n\t\t\t{renderedChildren}\r\n\t\t</div>\r\n\t);\r\n}\r\n\r\n/* ─────────────── Skeleton Children ─────────────── */\r\n\r\ninterface UseSkeletonChildrenParams {\r\n\tloading: boolean;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tid: string;\r\n}\r\n\r\n/**\r\n * Build the rendered children tree.\r\n *\r\n * Priority during `loading=true`:\r\n * 1. `as` set → render `dummyLength` (or 1) instances of `<as {...dummyData} />`.\r\n * Children ignored. Cold-start safe.\r\n * 2. `dummyData` set + children present → clone each child merging\r\n * dummyData over its props. If `dummyLength` set, clone first\r\n * templated child N times.\r\n * 3. None → pass children through (e.g. `useIsShimmering` flow).\r\n *\r\n * `loading=false` → children untouched.\r\n */\r\nfunction useSkeletonChildren({\r\n\tloading,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tid,\r\n}: UseSkeletonChildrenParams): React.ReactNode {\r\n\tif (!loading) return children;\r\n\r\n\tif (as) {\r\n\t\tconst count = dummyLength && dummyLength > 0 ? dummyLength : 1;\r\n\t\tconst Component = as;\r\n\t\treturn Array.from({ length: count }, (_, i) => (\r\n\t\t\t<Component\r\n\t\t\t\t{...(dummyData || {})}\r\n\t\t\t\tkey={generateShimmerKey(`${id}-as-${i}`)}\r\n\t\t\t/>\r\n\t\t));\r\n\t}\r\n\r\n\tconst childArray = React.Children.toArray(children);\r\n\r\n\tconst templated = childArray.map((c, i) => {\r\n\t\tif (!React.isValidElement(c)) return c;\r\n\t\tconst key = generateShimmerKey(`${id}-tpl-${i}`);\r\n\t\tconst props = dummyData ? { ...dummyData, key } : { key };\r\n\t\treturn React.cloneElement(c as React.ReactElement, props as any);\r\n\t});\r\n\r\n\tif (dummyLength && dummyLength > 0) {\r\n\t\tconst first = templated.find((c) => React.isValidElement(c)) as\r\n\t\t\t| React.ReactElement\r\n\t\t\t| undefined;\r\n\t\tif (!first) return null;\r\n\t\treturn Array.from({ length: dummyLength }, (_, i) =>\r\n\t\t\tReact.cloneElement(first, {\r\n\t\t\t\tkey: generateShimmerKey(`${id}-clone-${i}`),\r\n\t\t\t} as any),\r\n\t\t);\r\n\t}\r\n\r\n\treturn templated;\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { ShimmerConfig, ShimmerProps, DEFAULTS } from './types';\r\n\r\n/**\r\n * Factory function to create a pre-configured Shimmer component.\r\n * Avoids \"Provider Hell\" by baking config into the returned component.\r\n *\r\n * All config properties are optional — defaults are used for anything\r\n * not specified.\r\n *\r\n * @example\r\n * ```tsx\r\n * const AppShimmer = createShimmer({\r\n * animation: 'pulse',\r\n * baseColor: '#1a1a2e',\r\n * highlightColor: '#16213e',\r\n * speed: 2,\r\n * });\r\n *\r\n * <AppShimmer loading={isLoading}>\r\n * <MyComponent />\r\n * </AppShimmer>\r\n * ```\r\n */\r\nexport function createShimmer(config: ShimmerConfig = {}) {\r\n const mergedConfig: Required<ShimmerConfig> = {\r\n animation: config.animation ?? DEFAULTS.animation,\r\n baseColor: config.baseColor ?? DEFAULTS.baseColor,\r\n highlightColor: config.highlightColor ?? DEFAULTS.highlightColor,\r\n speed: config.speed ?? DEFAULTS.speed,\r\n borderRadius: config.borderRadius ?? DEFAULTS.borderRadius,\r\n preserveBackground: config.preserveBackground ?? DEFAULTS.preserveBackground,\r\n };\r\n\r\n function ConfiguredShimmer(props: Omit<ShimmerProps, keyof ShimmerConfig> & Partial<ShimmerConfig>) {\r\n return (\r\n <Shimmer\r\n {...mergedConfig}\r\n {...props}\r\n />\r\n );\r\n }\r\n\r\n // Removed ConfiguredShimmer.displayName\r\n return ConfiguredShimmer;\r\n}\r\n","'use client';\r\n\r\nimport React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { IsShimmeringContext } from './ShimmerContext';\r\nimport { ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerSuspenseProps extends ShimmerConfig {\r\n children: React.ReactNode;\r\n /**\r\n * Explicit skeleton template. Rendered hidden and traced for shimmer shape.\r\n *\r\n * Preferred — pass the same component with no data props:\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * If omitted, falls back to Option B: children are re-rendered with\r\n * `useIsShimmering()=true` so they can return an empty shape themselves.\r\n */\r\n template?: React.ReactNode;\r\n}\r\n\r\n/**\r\n * Suspense boundary that automatically shows a shimmer skeleton while\r\n * children are suspended (e.g. useSuspenseQuery, use(promise), etc).\r\n *\r\n * **Option A — explicit template (preferred):**\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * **Option B — useIsShimmering hook (no template):**\r\n * ```tsx\r\n * function UserCard() {\r\n * const isShimmering = useIsShimmering();\r\n * const data = isShimmering ? null : useSuspenseQuery(...);\r\n * return <div><h3>{data?.name}</h3></div>;\r\n * }\r\n *\r\n * <ShimmerSuspense>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n * Components must use `useIsShimmering()` to skip data fetching in shimmer mode,\r\n * otherwise they will also suspend inside the fallback (causing an empty skeleton).\r\n */\r\nexport function ShimmerSuspense({\r\n children,\r\n template,\r\n ...shimmerConfig\r\n}: ShimmerSuspenseProps) {\r\n const skeletonContent =\r\n template !== undefined ? (\r\n template\r\n ) : (\r\n <IsShimmeringContext.Provider value={true}>\r\n {children}\r\n </IsShimmeringContext.Provider>\r\n );\r\n\r\n return (\r\n <React.Suspense\r\n fallback={\r\n <Shimmer loading={true} {...shimmerConfig}>\r\n {skeletonContent}\r\n </Shimmer>\r\n }\r\n >\r\n {children}\r\n </React.Suspense>\r\n );\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shimmer-trace",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "High-performance React skeleton loaders that automatically trace your UI dimensions. Synchronized animations, zero CLS, and one-line implementation.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -53,11 +53,12 @@
53
53
  "react-dom": ">=18.0.0"
54
54
  },
55
55
  "devDependencies": {
56
+ "@types/node": "^25.9.1",
56
57
  "@types/react": "^19.1.3",
57
58
  "@types/react-dom": "^19.1.3",
59
+ "esbuild": "^0.25.0",
58
60
  "react": "^19.1.0",
59
61
  "react-dom": "^19.1.0",
60
- "esbuild": "^0.25.0",
61
62
  "tsup": "^8.5.0",
62
63
  "typescript": "^6.0.0"
63
64
  }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types.ts","../src/ShimmerContext.tsx","../src/ShimmerOverlay.tsx","../src/utils.ts","../src/useTrace.ts","../src/styles.ts","../src/Shimmer.tsx","../src/createShimmer.tsx","../src/ShimmerSuspense.tsx"],"names":["createContext","useContext","jsx","React","useState","useCallback","useLayoutEffect","useId","useMemo","useRef","jsxs","createElement"],"mappings":"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","file":"index.js","sourcesContent":["import React, { ReactNode } from 'react';\r\n\r\n/**\r\n * Represents a measured rectangle of a traced DOM element,\r\n * positioned relative to the Master Shimmer container.\r\n */\r\nexport interface ShimmerRect {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n borderRadius: string;\r\n}\r\n\r\n/** Available animation types for the shimmer effect. */\r\nexport type AnimationType =\r\n | 'wave'\r\n | 'pulse'\r\n | 'shine'\r\n | 'glow'\r\n | 'gradient';\r\n\r\n/** Configuration options for the shimmer effect (all optional). */\r\nexport interface ShimmerConfig {\r\n /** Animation style. Defaults to 'wave'. */\r\n animation?: AnimationType;\r\n /** Base color of the shimmer blocks. Defaults to '#e0e0e0'. */\r\n baseColor?: string;\r\n /** Highlight color of the shimmer animation. Defaults to '#f5f5f5'. */\r\n highlightColor?: string;\r\n /** Animation duration in seconds. Defaults to 1.5. */\r\n speed?: number;\r\n /** Global border-radius override. If omitted, auto-detected from each element (defaults to 4px if detection is 0px). */\r\n borderRadius?: string;\r\n /**\r\n * Keep container backgrounds, borders, and padding visible while loading.\r\n * When `true` (default), only text and media leaves are hidden via\r\n * `color:transparent` / `opacity:0` so card backgrounds, borders, and\r\n * spacing remain visible underneath the shimmer overlay.\r\n *\r\n * Set `false` for legacy behavior (`visibility:hidden` on whole tree).\r\n */\r\n preserveBackground?: boolean;\r\n}\r\n\r\n/** Props for the Shimmer component. */\r\nexport interface ShimmerProps extends ShimmerConfig {\r\n /** Whether the loading state is active. */\r\n loading?: boolean;\r\n /** The children to trace and render shimmer over. */\r\n children: ReactNode;\r\n /**\r\n * Number of placeholder clones to generate for list-like loading states.\r\n *\r\n * When `loading=true` and `dummyLength` is set, Shimmer grabs the first\r\n * available child (or a cached template from the last loaded render) and\r\n * clones it `dummyLength` times to produce skeleton placeholders.\r\n *\r\n * When `loading=false`, children are rendered as-is.\r\n */\r\n dummyLength?: number;\r\n /**\r\n * Props injected into each child element while `loading=true` so the\r\n * skeleton renders with realistic shape without requiring real data.\r\n *\r\n * Example:\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyData={{ user: { name: 'Loading...', role: '...', avatar: '' } }}\r\n * >\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * While loading, each direct child is cloned with these props merged on top\r\n * of its own props. Ignored when `loading=false`.\r\n */\r\n dummyData?: Record<string, any>;\r\n /**\r\n * Component used to auto-generate skeleton elements while `loading=true`.\r\n *\r\n * When set, Shimmer ignores `children` during loading and renders\r\n * `dummyLength` (defaults to 1) instances of `<as {...dummyData} />`\r\n * to derive shape. Real children render once `loading=false`.\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * as={MovieCard}\r\n * dummyData={{ movie: movieTemplate }}\r\n * dummyLength={10}\r\n * >\r\n * {movies.map((m) => <MovieCard movie={m} key={m.id} />)}\r\n * </Shimmer>\r\n * ```\r\n */\r\n as?: React.ComponentType<any>;\r\n /** Force this Shimmer to be a Master renderer even if nested inside another Shimmer. */\r\n stopPropagation?: boolean;\r\n /**\r\n * className applied to the Master container div.\r\n * Use to control layout (e.g. display:flex) without losing position:relative.\r\n */\r\n className?: string;\r\n /**\r\n * Inline styles merged into the Master container div.\r\n * position:relative is always applied; everything else is overridable.\r\n */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/** Default configuration values. */\r\nexport const DEFAULTS: Required<ShimmerConfig> = {\r\n animation: 'wave',\r\n baseColor: '#e0e0e0',\r\n highlightColor: '#f5f5f5',\r\n speed: 1.5,\r\n borderRadius: '',\r\n preserveBackground: true,\r\n};\r\n","import { createContext, useContext, RefObject } from 'react';\r\nimport { ShimmerRect, ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerContextValue {\r\n register: (id: string, rects: ShimmerRect[]) => void;\r\n unregister: (id: string) => void;\r\n /** Ref object (not .current) so Reporters always read a fresh value. */\r\n masterRef: RefObject<HTMLElement | null>;\r\n loading: boolean;\r\n config: Required<ShimmerConfig>;\r\n}\r\n\r\nexport const ShimmerContext = createContext<ShimmerContextValue | null>(null);\r\n\r\nexport function useShimmerContext(): ShimmerContextValue | null {\r\n return useContext(ShimmerContext);\r\n}\r\n\r\n/**\r\n * True when rendered inside a ShimmerSuspense fallback (Option B).\r\n * Components use this to skip data fetching and return an empty shape.\r\n */\r\nexport const IsShimmeringContext = createContext<boolean>(false);\r\n\r\nexport function useIsShimmering(): boolean {\r\n return useContext(IsShimmeringContext);\r\n}\r\n","import React from 'react';\r\nimport { ShimmerRect, AnimationType } from './types';\r\n\r\ninterface ShimmerOverlayProps {\r\n rects: ShimmerRect[];\r\n animation: AnimationType;\r\n baseColor: string;\r\n highlightColor: string;\r\n speed: number;\r\n}\r\n\r\n/**\r\n * Returns animation-specific inline styles for each shimmer block.\r\n * For sweep-style animations (wave, shine), the colored gradient is rendered\r\n * as a child layer so the sweep can extend across the container in sync.\r\n */\r\nfunction getBlockStyles(\r\n animation: AnimationType,\r\n baseColor: string,\r\n highlightColor: string,\r\n speed: number,\r\n rect: ShimmerRect,\r\n): React.CSSProperties {\r\n const base: React.CSSProperties = {\r\n position: 'absolute',\r\n top: rect.y,\r\n left: rect.x,\r\n width: rect.width,\r\n height: rect.height,\r\n borderRadius: rect.borderRadius,\r\n overflow: 'hidden',\r\n };\r\n\r\n switch (animation) {\r\n case 'wave':\r\n case 'shine':\r\n return { ...base, background: baseColor };\r\n case 'pulse':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-pulse ${speed}s ease-in-out infinite`,\r\n };\r\n case 'glow':\r\n return {\r\n ...base,\r\n background: baseColor,\r\n animation: `shimmer-glow ${speed}s ease-in-out infinite`,\r\n };\r\n case 'gradient':\r\n return {\r\n ...base,\r\n backgroundImage: `linear-gradient(90deg, ${baseColor}, ${highlightColor}, ${baseColor})`,\r\n backgroundSize: '200% 100%',\r\n animation: `shimmer-gradient ${speed * 1.5}s ease-in-out infinite`,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Sweeping shine layer used by `wave` and `shine` animations.\r\n * Spans the full container width so the highlight sweeps in sync across all blocks.\r\n */\r\nconst SweepLayer: React.FC<{\r\n rect: ShimmerRect;\r\n highlightColor: string;\r\n speed: number;\r\n containerWidth: number;\r\n variant: 'wave' | 'shine';\r\n}> = ({ rect, highlightColor, speed, containerWidth, variant }) => {\r\n const isShine = variant === 'shine';\r\n return (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: -rect.x,\r\n width: containerWidth > 0 ? containerWidth : '100vw',\r\n height: '100%',\r\n background: isShine\r\n ? `linear-gradient(115deg, transparent 30%, ${highlightColor} 50%, transparent 70%)`\r\n : `linear-gradient(90deg, transparent 0%, ${highlightColor} 50%, transparent 100%)`,\r\n animation: `${isShine ? 'shimmer-shine' : 'shimmer-wave'} ${speed}s ease-in-out infinite`,\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * The overlay component rendered by the Master Shimmer.\r\n *\r\n * Renders one absolutely-positioned div per traced rect. Sweep-style\r\n * animations (`wave`, `shine`) get an additional gradient layer that spans\r\n * the container so the highlight passes across all blocks in sync.\r\n */\r\nexport const ShimmerOverlay: React.FC<ShimmerOverlayProps> = ({\r\n rects,\r\n animation,\r\n baseColor,\r\n highlightColor,\r\n speed,\r\n}) => {\r\n const overlayRef = React.useRef<HTMLDivElement>(null);\r\n const [containerWidth, setContainerWidth] = React.useState(0);\r\n\r\n React.useLayoutEffect(() => {\r\n if (!overlayRef.current?.parentElement) return;\r\n setContainerWidth(overlayRef.current.parentElement.offsetWidth);\r\n }, [rects]);\r\n\r\n if (rects.length === 0) return null;\r\n\r\n const isSweep = animation === 'wave' || animation === 'shine';\r\n\r\n return (\r\n <div\r\n ref={overlayRef}\r\n role=\"status\"\r\n aria-busy=\"true\"\r\n aria-label=\"Loading content\"\r\n data-shimmer-ignore=\"true\"\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n zIndex: 1,\r\n pointerEvents: 'none',\r\n visibility: 'visible',\r\n }}\r\n >\r\n {rects.map((rect, i) => (\r\n <div\r\n key={i}\r\n style={getBlockStyles(animation, baseColor, highlightColor, speed, rect)}\r\n >\r\n {isSweep && (\r\n <SweepLayer\r\n rect={rect}\r\n highlightColor={highlightColor}\r\n speed={speed}\r\n containerWidth={containerWidth}\r\n variant={animation as 'wave' | 'shine'}\r\n />\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","/**\r\n * Generates a unique key for cloned elements to prevent\r\n * React \"missing key\" warnings during loading state.\r\n */\r\nlet counter = 0;\r\nexport function generateShimmerKey(prefix: string = 'shimmer'): string {\r\n return `${prefix}-clone-${++counter}`;\r\n}\r\n\r\n/**\r\n * Default fallback dimensions for common elements when their\r\n * measured dimensions are 0px (e.g., empty inputs, images not yet loaded).\r\n */\r\nexport const FALLBACK_DIMENSIONS: Record<string, { width: number; height: number }> = {\r\n INPUT: { width: 200, height: 36 },\r\n BUTTON: { width: 120, height: 36 },\r\n TEXTAREA: { width: 300, height: 80 },\r\n SELECT: { width: 200, height: 36 },\r\n IMG: { width: 100, height: 100 },\r\n H1: { width: 300, height: 36 },\r\n H2: { width: 260, height: 30 },\r\n H3: { width: 220, height: 26 },\r\n H4: { width: 200, height: 22 },\r\n H5: { width: 180, height: 20 },\r\n H6: { width: 160, height: 18 },\r\n P: { width: 250, height: 16 },\r\n SPAN: { width: 100, height: 16 },\r\n};\r\n","import { useLayoutEffect, useState, RefObject, useCallback } from 'react';\r\nimport { ShimmerRect } from './types';\r\nimport { FALLBACK_DIMENSIONS } from './utils';\r\n\r\n/**\r\n * Tags that are always considered \"traceable\" leaf elements\r\n * whose dimensions should be captured for the shimmer overlay.\r\n */\r\nconst TRACEABLE_TAGS = new Set([\r\n // Text\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LI',\r\n 'LABEL', 'TD', 'TH', 'BLOCKQUOTE', 'CODE', 'PRE',\r\n // Media\r\n 'IMG', 'VIDEO', 'SVG', 'CANVAS', 'PICTURE',\r\n // Form\r\n 'INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',\r\n // Misc\r\n 'HR',\r\n]);\r\n\r\n/**\r\n * Determines if an element should be traced.\r\n * Explicit data attributes override automatic detection.\r\n */\r\nfunction isTraceable(el: Element): boolean {\r\n if (el.hasAttribute('data-shimmer-ignore')) return false;\r\n if (el.hasAttribute('data-shimmer')) return true;\r\n if (TRACEABLE_TAGS.has(el.tagName)) return true;\r\n\r\n // Leaf element with visible dimensions → trace it\r\n if (el.children.length === 0) {\r\n const rect = el.getBoundingClientRect();\r\n return rect.width > 0 && rect.height > 0;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Recursively walks the DOM tree and collects all traceable elements.\r\n */\r\nfunction collectTraceableElements(root: Element): Element[] {\r\n const result: Element[] = [];\r\n\r\n function walk(el: Element) {\r\n if (el.hasAttribute('data-shimmer-ignore')) return;\r\n if (el.hasAttribute('data-shimmer-reporter')) return; // Ignore nested reporters, they report their own rects\r\n\r\n if (isTraceable(el)) {\r\n result.push(el);\r\n return; // Don't recurse into traced elements\r\n }\r\n\r\n for (let i = 0; i < el.children.length; i++) {\r\n walk(el.children[i]);\r\n }\r\n }\r\n\r\n for (let i = 0; i < root.children.length; i++) {\r\n walk(root.children[i]);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Measures an element and returns its ShimmerRect relative to the container.\r\n */\r\nfunction measureElement(\r\n el: Element,\r\n containerRect: DOMRect,\r\n globalBorderRadius?: string,\r\n): ShimmerRect | null {\r\n const elRect = el.getBoundingClientRect();\r\n\r\n // If the element is display: none or detached, getBoundingClientRect returns all zeros.\r\n // We must not trace it, otherwise it ends up at the left edge of the screen.\r\n if (elRect.width === 0 && elRect.height === 0 && elRect.left === 0 && elRect.top === 0) {\r\n return null;\r\n }\r\n\r\n const computedStyle = window.getComputedStyle(el);\r\n let borderRadius = globalBorderRadius || computedStyle.borderRadius;\r\n\r\n // If the element has no border radius (common for text tags),\r\n // apply a small default to avoid sharp edges in the shimmer.\r\n const isZero = !borderRadius || borderRadius === 'none' || borderRadius.split(' ').every(v => v === '0' || v === '0px' || v === '0%');\r\n if (isZero) {\r\n borderRadius = '4px';\r\n }\r\n\r\n let width = elRect.width;\r\n let height = elRect.height;\r\n\r\n // Apply fallback dimensions if element has 0 size but is actually visible (e.g. empty inline element)\r\n if (width === 0 || height === 0) {\r\n const fallback = FALLBACK_DIMENSIONS[el.tagName];\r\n if (fallback) {\r\n width = width || fallback.width;\r\n height = height || fallback.height;\r\n }\r\n }\r\n\r\n return {\r\n x: elRect.left - containerRect.left,\r\n y: elRect.top - containerRect.top,\r\n width,\r\n height,\r\n borderRadius,\r\n };\r\n}\r\n\r\n/**\r\n * Performs a full trace of all traceable elements within the container.\r\n *\r\n * @param anchorRef - When provided (Reporter mode), elements are measured\r\n * relative to this element instead of the container. Allows Reporter's\r\n * wrapper to use display:contents without breaking measurement.\r\n */\r\nfunction performTrace(\r\n container: HTMLElement,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const anchor = anchorRef?.current ?? container;\r\n const anchorRect = anchor.getBoundingClientRect();\r\n const elements = collectTraceableElements(container);\r\n\r\n return elements\r\n .map((el) => measureElement(el, anchorRect, globalBorderRadius))\r\n .filter((r): r is ShimmerRect => r !== null && r.width > 0 && r.height > 0);\r\n}\r\n\r\n/**\r\n * Hook that traces all visible leaf DOM elements within a container\r\n * and returns their measured ShimmerRects.\r\n *\r\n * Uses ResizeObserver to re-trace on container resize.\r\n *\r\n * @param anchorRef - When set, rects are relative to this element (Master).\r\n * Used by Reporter so its display:contents wrapper doesn't break measurement.\r\n */\r\nexport function useTrace(\r\n containerRef: RefObject<HTMLElement | null>,\r\n loading: boolean,\r\n globalBorderRadius?: string,\r\n anchorRef?: RefObject<HTMLElement | null>,\r\n): ShimmerRect[] {\r\n const [rects, setRects] = useState<ShimmerRect[]>([]);\r\n\r\n const trace = useCallback(() => {\r\n if (!containerRef.current) return;\r\n const traced = performTrace(containerRef.current, globalBorderRadius, anchorRef);\r\n setRects(traced);\r\n }, [containerRef, globalBorderRadius, anchorRef]);\r\n\r\n useLayoutEffect(() => {\r\n if (!loading || !containerRef.current) {\r\n setRects([]);\r\n return;\r\n }\r\n\r\n // Initial trace\r\n trace();\r\n\r\n // Re-trace on resize\r\n const observer = new ResizeObserver(() => {\r\n trace();\r\n });\r\n observer.observe(containerRef.current);\r\n\r\n return () => observer.disconnect();\r\n }, [loading, trace]);\r\n\r\n return rects;\r\n}\r\n","const SHIMMER_STYLES_ID = 'shimmer-trace-styles';\r\n\r\nconst CSS = `\r\n@keyframes shimmer-wave {\r\n 0% { transform: translateX(-100%); }\r\n 100% { transform: translateX(100%); }\r\n}\r\n\r\n@keyframes shimmer-pulse {\r\n 0%, 100% { opacity: 0.4; }\r\n 50% { opacity: 1; }\r\n}\r\n\r\n@keyframes shimmer-shine {\r\n 0% { transform: translateX(-150%) skewX(-20deg); }\r\n 100% { transform: translateX(150%) skewX(-20deg); }\r\n}\r\n\r\n@keyframes shimmer-glow {\r\n 0%, 100% { filter: brightness(1); }\r\n 50% { filter: brightness(1.35); }\r\n}\r\n\r\n@keyframes shimmer-gradient {\r\n 0% { background-position: 0% 50%; }\r\n 50% { background-position: 100% 50%; }\r\n 100% { background-position: 0% 50%; }\r\n}\r\n\r\n/* preserveBackground mode: hide text + media but keep container styles */\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(h1,h2,h3,h4,h5,h6,p,span,a,li,label,td,th,blockquote,code,pre,strong,em,small) {\r\n color: transparent !important;\r\n text-shadow: none !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(img,video,svg,canvas,picture) {\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] :is(input,textarea,select,button) {\r\n color: transparent !important;\r\n opacity: 0 !important;\r\n}\r\n[data-shimmer-master][data-shimmer-preserve-bg=\"true\"] {\r\n pointer-events: none !important;\r\n user-select: none !important;\r\n}\r\n`;\r\n\r\n/**\r\n * Injects the shimmer keyframe animations into the document head.\r\n * Safe to call multiple times — only injects once.\r\n */\r\nexport function injectStyles(): void {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById(SHIMMER_STYLES_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = SHIMMER_STYLES_ID;\r\n style.textContent = CSS;\r\n document.head.appendChild(style);\r\n}\r\n","import React, { useRef, useCallback, useState, useId, useMemo } from \"react\";\r\nimport { ShimmerProps, ShimmerRect, DEFAULTS } from \"./types\";\r\nimport { ShimmerContext, useShimmerContext } from \"./ShimmerContext\";\r\nimport { ShimmerOverlay } from \"./ShimmerOverlay\";\r\nimport { useTrace } from \"./useTrace\";\r\nimport { injectStyles } from \"./styles\";\r\nimport { generateShimmerKey } from \"./utils\";\r\n\r\n/**\r\n * The main Shimmer component.\r\n *\r\n * Auto-detects **Master** (no parent Shimmer) vs **Reporter** (nested).\r\n * - Master: renders children hidden, traces DOM, paints overlay.\r\n * - Reporter: measures own rects, reports to parent Master.\r\n *\r\n * ### Skeleton shape via `dummyData`\r\n *\r\n * Pass `dummyData` so children render with realistic data while loading.\r\n * No render-prop, no manual `data || fallback` in JSX.\r\n *\r\n * ```tsx\r\n * const userTemplate = { name: 'Loading...', role: '...', avatar: '' };\r\n *\r\n * <Shimmer loading={loading} dummyData={{ user: userTemplate }}>\r\n * <UserCard user={user} />\r\n * </Shimmer>\r\n * ```\r\n *\r\n * ### List mode (`dummyLength`)\r\n *\r\n * Combined with `dummyData`, clones the first child N times with\r\n * template props merged in:\r\n *\r\n * ```tsx\r\n * <Shimmer\r\n * loading={loading}\r\n * dummyLength={5}\r\n * dummyData={{ fruit: { name: 'xxxxx', price: '$0.00' } }}\r\n * >\r\n * <FruitCard fruit={undefined as any} />\r\n * </Shimmer>\r\n * ```\r\n */\r\nexport function Shimmer({\r\n\tloading = false,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tstopPropagation = false,\r\n\tanimation,\r\n\tbaseColor,\r\n\thighlightColor,\r\n\tspeed,\r\n\tborderRadius,\r\n\tpreserveBackground,\r\n\tclassName,\r\n\tstyle,\r\n}: ShimmerProps) {\r\n\tconst parentContext = useShimmerContext();\r\n\tconst isMaster = !parentContext || stopPropagation;\r\n\tconst id = useId();\r\n\r\n\tconst config = useMemo(\r\n\t\t() => ({\r\n\t\t\tanimation:\r\n\t\t\t\tanimation ?? parentContext?.config.animation ?? DEFAULTS.animation,\r\n\t\t\tbaseColor:\r\n\t\t\t\tbaseColor ?? parentContext?.config.baseColor ?? DEFAULTS.baseColor,\r\n\t\t\thighlightColor:\r\n\t\t\t\thighlightColor ??\r\n\t\t\t\tparentContext?.config.highlightColor ??\r\n\t\t\t\tDEFAULTS.highlightColor,\r\n\t\t\tspeed: speed ?? parentContext?.config.speed ?? DEFAULTS.speed,\r\n\t\t\tborderRadius:\r\n\t\t\t\tborderRadius ??\r\n\t\t\t\tparentContext?.config.borderRadius ??\r\n\t\t\t\tDEFAULTS.borderRadius,\r\n\t\t\tpreserveBackground:\r\n\t\t\t\tpreserveBackground ??\r\n\t\t\t\tparentContext?.config.preserveBackground ??\r\n\t\t\t\tDEFAULTS.preserveBackground,\r\n\t\t}),\r\n\t\t[\r\n\t\t\tanimation,\r\n\t\t\tbaseColor,\r\n\t\t\thighlightColor,\r\n\t\t\tspeed,\r\n\t\t\tborderRadius,\r\n\t\t\tpreserveBackground,\r\n\t\t\tparentContext?.config,\r\n\t\t],\r\n\t);\r\n\r\n\tif (isMaster) {\r\n\t\treturn (\r\n\t\t\t<MasterShimmer\r\n\t\t\t\tid={id}\r\n\t\t\t\tloading={loading}\r\n\t\t\t\tconfig={config}\r\n\t\t\t\tdummyLength={dummyLength}\r\n\t\t\t\tdummyData={dummyData}\r\n\t\t\t\tas={as}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={style}\r\n\t\t\t>\r\n\t\t\t\t{children}\r\n\t\t\t</MasterShimmer>\r\n\t\t);\r\n\t}\r\n\r\n\treturn (\r\n\t\t<ReporterShimmer\r\n\t\t\tid={id}\r\n\t\t\tparentContext={parentContext!}\r\n\t\t\tconfig={config}\r\n\t\t\tdummyLength={dummyLength}\r\n\t\t\tdummyData={dummyData}\r\n\t\t\tas={as}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</ReporterShimmer>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Master ─────────────────── */\r\n\r\ninterface MasterShimmerProps {\r\n\tid: string;\r\n\tloading: boolean;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\nfunction MasterShimmer({\r\n\tid,\r\n\tloading,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tclassName,\r\n\tstyle,\r\n}: MasterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst [reporterRects, setReporterRects] = useState<\r\n\t\tRecord<string, ShimmerRect[]>\r\n\t>({});\r\n\r\n\tconst register = useCallback((rid: string, rects: ShimmerRect[]) => {\r\n\t\tsetReporterRects((prev) => ({ ...prev, [rid]: rects }));\r\n\t}, []);\r\n\r\n\tconst unregister = useCallback((rid: string) => {\r\n\t\tsetReporterRects((prev) => {\r\n\t\t\tconst next = { ...prev };\r\n\t\t\tdelete next[rid];\r\n\t\t\treturn next;\r\n\t\t});\r\n\t}, []);\r\n\r\n\tReact.useEffect(() => {\r\n\t\tinjectStyles();\r\n\t}, []);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tloading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t);\r\n\r\n\tconst allRects = useMemo(() => {\r\n\t\tconst reported = Object.values(reporterRects).flat();\r\n\t\treturn [...tracedRects, ...reported];\r\n\t}, [tracedRects, reporterRects]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\tconst contextValue = useMemo(\r\n\t\t() => ({\r\n\t\t\tregister,\r\n\t\t\tunregister,\r\n\t\t\tmasterRef: containerRef,\r\n\t\t\tloading,\r\n\t\t\tconfig,\r\n\t\t}),\r\n\t\t[register, unregister, loading, config],\r\n\t);\r\n\r\n\treturn (\r\n\t\t<ShimmerContext.Provider value={contextValue}>\r\n\t\t\t<div\r\n\t\t\t\tref={containerRef}\r\n\t\t\t\tclassName={className}\r\n\t\t\t\tstyle={{\r\n\t\t\t\t\tposition: \"relative\",\r\n\t\t\t\t\tvisibility:\r\n\t\t\t\t\t\tloading && !config.preserveBackground ? \"hidden\" : undefined,\r\n\t\t\t\t\t...style,\r\n\t\t\t\t}}\r\n\t\t\t\taria-hidden={loading || undefined}\r\n\t\t\t\tdata-shimmer-master\r\n\t\t\t\tdata-shimmer-preserve-bg={\r\n\t\t\t\t\tloading && config.preserveBackground ? \"true\" : undefined\r\n\t\t\t\t}\r\n\t\t\t>\r\n\t\t\t\t{renderedChildren}\r\n\r\n\t\t\t\t{loading && (\r\n\t\t\t\t\t<ShimmerOverlay\r\n\t\t\t\t\t\trects={allRects}\r\n\t\t\t\t\t\tanimation={config.animation}\r\n\t\t\t\t\t\tbaseColor={config.baseColor}\r\n\t\t\t\t\t\thighlightColor={config.highlightColor}\r\n\t\t\t\t\t\tspeed={config.speed}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t</div>\r\n\t\t</ShimmerContext.Provider>\r\n\t);\r\n}\r\n\r\n/* ─────────────────── Reporter ─────────────────── */\r\n\r\ninterface ReporterShimmerProps {\r\n\tid: string;\r\n\tparentContext: NonNullable<ReturnType<typeof useShimmerContext>>;\r\n\tconfig: Required<typeof DEFAULTS>;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n}\r\n\r\nfunction ReporterShimmer({\r\n\tid,\r\n\tparentContext,\r\n\tconfig,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n}: ReporterShimmerProps) {\r\n\tconst containerRef = useRef<HTMLDivElement>(null);\r\n\r\n\tconst tracedRects = useTrace(\r\n\t\tcontainerRef,\r\n\t\tparentContext.loading,\r\n\t\tconfig.borderRadius || undefined,\r\n\t\tparentContext.masterRef,\r\n\t);\r\n\r\n\tReact.useLayoutEffect(() => {\r\n\t\tif (!parentContext.loading || tracedRects.length === 0) {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tparentContext.register(id, tracedRects);\r\n\t\treturn () => {\r\n\t\t\tparentContext.unregister(id);\r\n\t\t};\r\n\t}, [tracedRects, parentContext, id]);\r\n\r\n\tconst renderedChildren = useSkeletonChildren({\r\n\t\tloading: parentContext.loading,\r\n\t\tchildren,\r\n\t\tdummyLength,\r\n\t\tdummyData,\r\n\t\tas,\r\n\t\tid,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<div\r\n\t\t\tref={containerRef}\r\n\t\t\tdata-shimmer-reporter\r\n\t\t\tstyle={{ display: \"contents\" }}\r\n\t\t>\r\n\t\t\t{renderedChildren}\r\n\t\t</div>\r\n\t);\r\n}\r\n\r\n/* ─────────────── Skeleton Children ─────────────── */\r\n\r\ninterface UseSkeletonChildrenParams {\r\n\tloading: boolean;\r\n\tchildren: React.ReactNode;\r\n\tdummyLength?: number;\r\n\tdummyData?: Record<string, any>;\r\n\tas?: React.ComponentType<any>;\r\n\tid: string;\r\n}\r\n\r\n/**\r\n * Build the rendered children tree.\r\n *\r\n * Priority during `loading=true`:\r\n * 1. `as` set → render `dummyLength` (or 1) instances of `<as {...dummyData} />`.\r\n * Children ignored. Cold-start safe.\r\n * 2. `dummyData` set + children present → clone each child merging\r\n * dummyData over its props. If `dummyLength` set, clone first\r\n * templated child N times.\r\n * 3. None → pass children through (e.g. `useIsShimmering` flow).\r\n *\r\n * `loading=false` → children untouched.\r\n */\r\nfunction useSkeletonChildren({\r\n\tloading,\r\n\tchildren,\r\n\tdummyLength,\r\n\tdummyData,\r\n\tas,\r\n\tid,\r\n}: UseSkeletonChildrenParams): React.ReactNode {\r\n\tif (!loading) return children;\r\n\r\n\tif (as) {\r\n\t\tconst count = dummyLength && dummyLength > 0 ? dummyLength : 1;\r\n\t\tconst Component = as;\r\n\t\treturn Array.from({ length: count }, (_, i) => (\r\n\t\t\t<Component\r\n\t\t\t\t{...(dummyData || {})}\r\n\t\t\t\tkey={generateShimmerKey(`${id}-as-${i}`)}\r\n\t\t\t/>\r\n\t\t));\r\n\t}\r\n\r\n\tconst childArray = React.Children.toArray(children);\r\n\r\n\tconst templated = childArray.map((c, i) => {\r\n\t\tif (!React.isValidElement(c)) return c;\r\n\t\tconst key = generateShimmerKey(`${id}-tpl-${i}`);\r\n\t\tconst props = dummyData ? { ...dummyData, key } : { key };\r\n\t\treturn React.cloneElement(c as React.ReactElement, props as any);\r\n\t});\r\n\r\n\tif (dummyLength && dummyLength > 0) {\r\n\t\tconst first = templated.find((c) => React.isValidElement(c)) as\r\n\t\t\t| React.ReactElement\r\n\t\t\t| undefined;\r\n\t\tif (!first) return null;\r\n\t\treturn Array.from({ length: dummyLength }, (_, i) =>\r\n\t\t\tReact.cloneElement(first, {\r\n\t\t\t\tkey: generateShimmerKey(`${id}-clone-${i}`),\r\n\t\t\t} as any),\r\n\t\t);\r\n\t}\r\n\r\n\treturn templated;\r\n}\r\n","import React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { ShimmerConfig, ShimmerProps, DEFAULTS } from './types';\r\n\r\n/**\r\n * Factory function to create a pre-configured Shimmer component.\r\n * Avoids \"Provider Hell\" by baking config into the returned component.\r\n *\r\n * All config properties are optional — defaults are used for anything\r\n * not specified.\r\n *\r\n * @example\r\n * ```tsx\r\n * const AppShimmer = createShimmer({\r\n * animation: 'pulse',\r\n * baseColor: '#1a1a2e',\r\n * highlightColor: '#16213e',\r\n * speed: 2,\r\n * });\r\n *\r\n * <AppShimmer loading={isLoading}>\r\n * <MyComponent />\r\n * </AppShimmer>\r\n * ```\r\n */\r\nexport function createShimmer(config: ShimmerConfig = {}) {\r\n const mergedConfig: Required<ShimmerConfig> = {\r\n animation: config.animation ?? DEFAULTS.animation,\r\n baseColor: config.baseColor ?? DEFAULTS.baseColor,\r\n highlightColor: config.highlightColor ?? DEFAULTS.highlightColor,\r\n speed: config.speed ?? DEFAULTS.speed,\r\n borderRadius: config.borderRadius ?? DEFAULTS.borderRadius,\r\n preserveBackground: config.preserveBackground ?? DEFAULTS.preserveBackground,\r\n };\r\n\r\n function ConfiguredShimmer(props: Omit<ShimmerProps, keyof ShimmerConfig> & Partial<ShimmerConfig>) {\r\n return (\r\n <Shimmer\r\n {...mergedConfig}\r\n {...props}\r\n />\r\n );\r\n }\r\n\r\n // Removed ConfiguredShimmer.displayName\r\n return ConfiguredShimmer;\r\n}\r\n","import React from 'react';\r\nimport { Shimmer } from './Shimmer';\r\nimport { IsShimmeringContext } from './ShimmerContext';\r\nimport { ShimmerConfig } from './types';\r\n\r\nexport interface ShimmerSuspenseProps extends ShimmerConfig {\r\n children: React.ReactNode;\r\n /**\r\n * Explicit skeleton template. Rendered hidden and traced for shimmer shape.\r\n *\r\n * Preferred — pass the same component with no data props:\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * If omitted, falls back to Option B: children are re-rendered with\r\n * `useIsShimmering()=true` so they can return an empty shape themselves.\r\n */\r\n template?: React.ReactNode;\r\n}\r\n\r\n/**\r\n * Suspense boundary that automatically shows a shimmer skeleton while\r\n * children are suspended (e.g. useSuspenseQuery, use(promise), etc).\r\n *\r\n * **Option A — explicit template (preferred):**\r\n * ```tsx\r\n * <ShimmerSuspense template={<UserCard />}>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n *\r\n * **Option B — useIsShimmering hook (no template):**\r\n * ```tsx\r\n * function UserCard() {\r\n * const isShimmering = useIsShimmering();\r\n * const data = isShimmering ? null : useSuspenseQuery(...);\r\n * return <div><h3>{data?.name}</h3></div>;\r\n * }\r\n *\r\n * <ShimmerSuspense>\r\n * <UserCard />\r\n * </ShimmerSuspense>\r\n * ```\r\n * Components must use `useIsShimmering()` to skip data fetching in shimmer mode,\r\n * otherwise they will also suspend inside the fallback (causing an empty skeleton).\r\n */\r\nexport function ShimmerSuspense({\r\n children,\r\n template,\r\n ...shimmerConfig\r\n}: ShimmerSuspenseProps) {\r\n const skeletonContent =\r\n template !== undefined ? (\r\n template\r\n ) : (\r\n <IsShimmeringContext.Provider value={true}>\r\n {children}\r\n </IsShimmeringContext.Provider>\r\n );\r\n\r\n return (\r\n <React.Suspense\r\n fallback={\r\n <Shimmer loading={true} {...shimmerConfig}>\r\n {skeletonContent}\r\n </Shimmer>\r\n }\r\n >\r\n {children}\r\n </React.Suspense>\r\n );\r\n}\r\n"]}