shimmer-trace 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +657 -0
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/dist/index.d.mts +224 -0
- package/dist/index.d.ts +224 -0
- package/dist/index.js +601 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +590 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React2 = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
9
|
+
|
|
10
|
+
// src/Shimmer.tsx
|
|
11
|
+
|
|
12
|
+
// src/types.ts
|
|
13
|
+
var DEFAULTS = {
|
|
14
|
+
animation: "wave",
|
|
15
|
+
baseColor: "#e0e0e0",
|
|
16
|
+
highlightColor: "#f5f5f5",
|
|
17
|
+
speed: 1.5,
|
|
18
|
+
borderRadius: "",
|
|
19
|
+
preserveBackground: true
|
|
20
|
+
};
|
|
21
|
+
var ShimmerContext = React2.createContext(null);
|
|
22
|
+
function useShimmerContext() {
|
|
23
|
+
return React2.useContext(ShimmerContext);
|
|
24
|
+
}
|
|
25
|
+
var IsShimmeringContext = React2.createContext(false);
|
|
26
|
+
function useIsShimmering() {
|
|
27
|
+
return React2.useContext(IsShimmeringContext);
|
|
28
|
+
}
|
|
29
|
+
function getBlockStyles(animation, baseColor, highlightColor, speed, rect) {
|
|
30
|
+
const base = {
|
|
31
|
+
position: "absolute",
|
|
32
|
+
top: rect.y,
|
|
33
|
+
left: rect.x,
|
|
34
|
+
width: rect.width,
|
|
35
|
+
height: rect.height,
|
|
36
|
+
borderRadius: rect.borderRadius,
|
|
37
|
+
overflow: "hidden"
|
|
38
|
+
};
|
|
39
|
+
switch (animation) {
|
|
40
|
+
case "wave":
|
|
41
|
+
case "shine":
|
|
42
|
+
return { ...base, background: baseColor };
|
|
43
|
+
case "pulse":
|
|
44
|
+
return {
|
|
45
|
+
...base,
|
|
46
|
+
background: baseColor,
|
|
47
|
+
animation: `shimmer-pulse ${speed}s ease-in-out infinite`
|
|
48
|
+
};
|
|
49
|
+
case "glow":
|
|
50
|
+
return {
|
|
51
|
+
...base,
|
|
52
|
+
background: baseColor,
|
|
53
|
+
animation: `shimmer-glow ${speed}s ease-in-out infinite`
|
|
54
|
+
};
|
|
55
|
+
case "gradient":
|
|
56
|
+
return {
|
|
57
|
+
...base,
|
|
58
|
+
backgroundImage: `linear-gradient(90deg, ${baseColor}, ${highlightColor}, ${baseColor})`,
|
|
59
|
+
backgroundSize: "200% 100%",
|
|
60
|
+
animation: `shimmer-gradient ${speed * 1.5}s ease-in-out infinite`
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var SweepLayer = ({ rect, highlightColor, speed, containerWidth, variant }) => {
|
|
65
|
+
const isShine = variant === "shine";
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
style: {
|
|
70
|
+
position: "absolute",
|
|
71
|
+
top: 0,
|
|
72
|
+
left: -rect.x,
|
|
73
|
+
width: containerWidth > 0 ? containerWidth : "100vw",
|
|
74
|
+
height: "100%",
|
|
75
|
+
background: isShine ? `linear-gradient(115deg, transparent 30%, ${highlightColor} 50%, transparent 70%)` : `linear-gradient(90deg, transparent 0%, ${highlightColor} 50%, transparent 100%)`,
|
|
76
|
+
animation: `${isShine ? "shimmer-shine" : "shimmer-wave"} ${speed}s ease-in-out infinite`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
var ShimmerOverlay = ({
|
|
82
|
+
rects,
|
|
83
|
+
animation,
|
|
84
|
+
baseColor,
|
|
85
|
+
highlightColor,
|
|
86
|
+
speed
|
|
87
|
+
}) => {
|
|
88
|
+
const overlayRef = React2__default.default.useRef(null);
|
|
89
|
+
const [containerWidth, setContainerWidth] = React2__default.default.useState(0);
|
|
90
|
+
React2__default.default.useLayoutEffect(() => {
|
|
91
|
+
if (!overlayRef.current?.parentElement) return;
|
|
92
|
+
setContainerWidth(overlayRef.current.parentElement.offsetWidth);
|
|
93
|
+
}, [rects]);
|
|
94
|
+
if (rects.length === 0) return null;
|
|
95
|
+
const isSweep = animation === "wave" || animation === "shine";
|
|
96
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
97
|
+
"div",
|
|
98
|
+
{
|
|
99
|
+
ref: overlayRef,
|
|
100
|
+
role: "status",
|
|
101
|
+
"aria-busy": "true",
|
|
102
|
+
"aria-label": "Loading content",
|
|
103
|
+
"data-shimmer-ignore": "true",
|
|
104
|
+
style: {
|
|
105
|
+
position: "absolute",
|
|
106
|
+
top: 0,
|
|
107
|
+
left: 0,
|
|
108
|
+
width: "100%",
|
|
109
|
+
height: "100%",
|
|
110
|
+
zIndex: 1,
|
|
111
|
+
pointerEvents: "none",
|
|
112
|
+
visibility: "visible"
|
|
113
|
+
},
|
|
114
|
+
children: rects.map((rect, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
115
|
+
"div",
|
|
116
|
+
{
|
|
117
|
+
style: getBlockStyles(animation, baseColor, highlightColor, speed, rect),
|
|
118
|
+
children: isSweep && /* @__PURE__ */ jsxRuntime.jsx(
|
|
119
|
+
SweepLayer,
|
|
120
|
+
{
|
|
121
|
+
rect,
|
|
122
|
+
highlightColor,
|
|
123
|
+
speed,
|
|
124
|
+
containerWidth,
|
|
125
|
+
variant: animation
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
},
|
|
129
|
+
i
|
|
130
|
+
))
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/utils.ts
|
|
136
|
+
var counter = 0;
|
|
137
|
+
function generateShimmerKey(prefix = "shimmer") {
|
|
138
|
+
return `${prefix}-clone-${++counter}`;
|
|
139
|
+
}
|
|
140
|
+
var FALLBACK_DIMENSIONS = {
|
|
141
|
+
INPUT: { width: 200, height: 36 },
|
|
142
|
+
BUTTON: { width: 120, height: 36 },
|
|
143
|
+
TEXTAREA: { width: 300, height: 80 },
|
|
144
|
+
SELECT: { width: 200, height: 36 },
|
|
145
|
+
IMG: { width: 100, height: 100 },
|
|
146
|
+
H1: { width: 300, height: 36 },
|
|
147
|
+
H2: { width: 260, height: 30 },
|
|
148
|
+
H3: { width: 220, height: 26 },
|
|
149
|
+
H4: { width: 200, height: 22 },
|
|
150
|
+
H5: { width: 180, height: 20 },
|
|
151
|
+
H6: { width: 160, height: 18 },
|
|
152
|
+
P: { width: 250, height: 16 },
|
|
153
|
+
SPAN: { width: 100, height: 16 }
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// src/useTrace.ts
|
|
157
|
+
var TRACEABLE_TAGS = /* @__PURE__ */ new Set([
|
|
158
|
+
// Text
|
|
159
|
+
"H1",
|
|
160
|
+
"H2",
|
|
161
|
+
"H3",
|
|
162
|
+
"H4",
|
|
163
|
+
"H5",
|
|
164
|
+
"H6",
|
|
165
|
+
"P",
|
|
166
|
+
"SPAN",
|
|
167
|
+
"A",
|
|
168
|
+
"LI",
|
|
169
|
+
"LABEL",
|
|
170
|
+
"TD",
|
|
171
|
+
"TH",
|
|
172
|
+
"BLOCKQUOTE",
|
|
173
|
+
"CODE",
|
|
174
|
+
"PRE",
|
|
175
|
+
// Media
|
|
176
|
+
"IMG",
|
|
177
|
+
"VIDEO",
|
|
178
|
+
"SVG",
|
|
179
|
+
"CANVAS",
|
|
180
|
+
"PICTURE",
|
|
181
|
+
// Form
|
|
182
|
+
"INPUT",
|
|
183
|
+
"TEXTAREA",
|
|
184
|
+
"SELECT",
|
|
185
|
+
"BUTTON",
|
|
186
|
+
// Misc
|
|
187
|
+
"HR"
|
|
188
|
+
]);
|
|
189
|
+
function isTraceable(el) {
|
|
190
|
+
if (el.hasAttribute("data-shimmer-ignore")) return false;
|
|
191
|
+
if (el.hasAttribute("data-shimmer")) return true;
|
|
192
|
+
if (TRACEABLE_TAGS.has(el.tagName)) return true;
|
|
193
|
+
if (el.children.length === 0) {
|
|
194
|
+
const rect = el.getBoundingClientRect();
|
|
195
|
+
return rect.width > 0 && rect.height > 0;
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
function collectTraceableElements(root) {
|
|
200
|
+
const result = [];
|
|
201
|
+
function walk(el) {
|
|
202
|
+
if (el.hasAttribute("data-shimmer-ignore")) return;
|
|
203
|
+
if (el.hasAttribute("data-shimmer-reporter")) return;
|
|
204
|
+
if (isTraceable(el)) {
|
|
205
|
+
result.push(el);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
209
|
+
walk(el.children[i]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (let i = 0; i < root.children.length; i++) {
|
|
213
|
+
walk(root.children[i]);
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
function measureElement(el, containerRect, globalBorderRadius) {
|
|
218
|
+
const elRect = el.getBoundingClientRect();
|
|
219
|
+
if (elRect.width === 0 && elRect.height === 0 && elRect.left === 0 && elRect.top === 0) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
const computedStyle = window.getComputedStyle(el);
|
|
223
|
+
let borderRadius = globalBorderRadius || computedStyle.borderRadius;
|
|
224
|
+
const isZero = !borderRadius || borderRadius === "none" || borderRadius.split(" ").every((v) => v === "0" || v === "0px" || v === "0%");
|
|
225
|
+
if (isZero) {
|
|
226
|
+
borderRadius = "4px";
|
|
227
|
+
}
|
|
228
|
+
let width = elRect.width;
|
|
229
|
+
let height = elRect.height;
|
|
230
|
+
if (width === 0 || height === 0) {
|
|
231
|
+
const fallback = FALLBACK_DIMENSIONS[el.tagName];
|
|
232
|
+
if (fallback) {
|
|
233
|
+
width = width || fallback.width;
|
|
234
|
+
height = height || fallback.height;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
x: elRect.left - containerRect.left,
|
|
239
|
+
y: elRect.top - containerRect.top,
|
|
240
|
+
width,
|
|
241
|
+
height,
|
|
242
|
+
borderRadius
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function performTrace(container, globalBorderRadius, anchorRef) {
|
|
246
|
+
const anchor = anchorRef?.current ?? container;
|
|
247
|
+
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);
|
|
250
|
+
}
|
|
251
|
+
function useTrace(containerRef, loading, globalBorderRadius, anchorRef) {
|
|
252
|
+
const [rects, setRects] = React2.useState([]);
|
|
253
|
+
const trace = React2.useCallback(() => {
|
|
254
|
+
if (!containerRef.current) return;
|
|
255
|
+
const traced = performTrace(containerRef.current, globalBorderRadius, anchorRef);
|
|
256
|
+
setRects(traced);
|
|
257
|
+
}, [containerRef, globalBorderRadius, anchorRef]);
|
|
258
|
+
React2.useLayoutEffect(() => {
|
|
259
|
+
if (!loading || !containerRef.current) {
|
|
260
|
+
setRects([]);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
trace();
|
|
264
|
+
const observer = new ResizeObserver(() => {
|
|
265
|
+
trace();
|
|
266
|
+
});
|
|
267
|
+
observer.observe(containerRef.current);
|
|
268
|
+
return () => observer.disconnect();
|
|
269
|
+
}, [loading, trace]);
|
|
270
|
+
return rects;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/styles.ts
|
|
274
|
+
var SHIMMER_STYLES_ID = "shimmer-trace-styles";
|
|
275
|
+
var CSS = `
|
|
276
|
+
@keyframes shimmer-wave {
|
|
277
|
+
0% { transform: translateX(-100%); }
|
|
278
|
+
100% { transform: translateX(100%); }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@keyframes shimmer-pulse {
|
|
282
|
+
0%, 100% { opacity: 0.4; }
|
|
283
|
+
50% { opacity: 1; }
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
@keyframes shimmer-shine {
|
|
287
|
+
0% { transform: translateX(-150%) skewX(-20deg); }
|
|
288
|
+
100% { transform: translateX(150%) skewX(-20deg); }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@keyframes shimmer-glow {
|
|
292
|
+
0%, 100% { filter: brightness(1); }
|
|
293
|
+
50% { filter: brightness(1.35); }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
@keyframes shimmer-gradient {
|
|
297
|
+
0% { background-position: 0% 50%; }
|
|
298
|
+
50% { background-position: 100% 50%; }
|
|
299
|
+
100% { background-position: 0% 50%; }
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* preserveBackground mode: hide text + media but keep container styles */
|
|
303
|
+
[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) {
|
|
304
|
+
color: transparent !important;
|
|
305
|
+
text-shadow: none !important;
|
|
306
|
+
}
|
|
307
|
+
[data-shimmer-master][data-shimmer-preserve-bg="true"] :is(img,video,svg,canvas,picture) {
|
|
308
|
+
opacity: 0 !important;
|
|
309
|
+
}
|
|
310
|
+
[data-shimmer-master][data-shimmer-preserve-bg="true"] :is(input,textarea,select,button) {
|
|
311
|
+
color: transparent !important;
|
|
312
|
+
opacity: 0 !important;
|
|
313
|
+
}
|
|
314
|
+
[data-shimmer-master][data-shimmer-preserve-bg="true"] {
|
|
315
|
+
pointer-events: none !important;
|
|
316
|
+
user-select: none !important;
|
|
317
|
+
}
|
|
318
|
+
`;
|
|
319
|
+
function injectStyles() {
|
|
320
|
+
if (typeof document === "undefined") return;
|
|
321
|
+
if (document.getElementById(SHIMMER_STYLES_ID)) return;
|
|
322
|
+
const style = document.createElement("style");
|
|
323
|
+
style.id = SHIMMER_STYLES_ID;
|
|
324
|
+
style.textContent = CSS;
|
|
325
|
+
document.head.appendChild(style);
|
|
326
|
+
}
|
|
327
|
+
function Shimmer({
|
|
328
|
+
loading = false,
|
|
329
|
+
children,
|
|
330
|
+
dummyLength,
|
|
331
|
+
dummyData,
|
|
332
|
+
as,
|
|
333
|
+
stopPropagation = false,
|
|
334
|
+
animation,
|
|
335
|
+
baseColor,
|
|
336
|
+
highlightColor,
|
|
337
|
+
speed,
|
|
338
|
+
borderRadius,
|
|
339
|
+
preserveBackground,
|
|
340
|
+
className,
|
|
341
|
+
style
|
|
342
|
+
}) {
|
|
343
|
+
const parentContext = useShimmerContext();
|
|
344
|
+
const isMaster = !parentContext || stopPropagation;
|
|
345
|
+
const id = React2.useId();
|
|
346
|
+
const config = React2.useMemo(
|
|
347
|
+
() => ({
|
|
348
|
+
animation: animation ?? parentContext?.config.animation ?? DEFAULTS.animation,
|
|
349
|
+
baseColor: baseColor ?? parentContext?.config.baseColor ?? DEFAULTS.baseColor,
|
|
350
|
+
highlightColor: highlightColor ?? parentContext?.config.highlightColor ?? DEFAULTS.highlightColor,
|
|
351
|
+
speed: speed ?? parentContext?.config.speed ?? DEFAULTS.speed,
|
|
352
|
+
borderRadius: borderRadius ?? parentContext?.config.borderRadius ?? DEFAULTS.borderRadius,
|
|
353
|
+
preserveBackground: preserveBackground ?? parentContext?.config.preserveBackground ?? DEFAULTS.preserveBackground
|
|
354
|
+
}),
|
|
355
|
+
[
|
|
356
|
+
animation,
|
|
357
|
+
baseColor,
|
|
358
|
+
highlightColor,
|
|
359
|
+
speed,
|
|
360
|
+
borderRadius,
|
|
361
|
+
preserveBackground,
|
|
362
|
+
parentContext?.config
|
|
363
|
+
]
|
|
364
|
+
);
|
|
365
|
+
if (isMaster) {
|
|
366
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
367
|
+
MasterShimmer,
|
|
368
|
+
{
|
|
369
|
+
id,
|
|
370
|
+
loading,
|
|
371
|
+
config,
|
|
372
|
+
dummyLength,
|
|
373
|
+
dummyData,
|
|
374
|
+
as,
|
|
375
|
+
className,
|
|
376
|
+
style,
|
|
377
|
+
children
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
382
|
+
ReporterShimmer,
|
|
383
|
+
{
|
|
384
|
+
id,
|
|
385
|
+
parentContext,
|
|
386
|
+
config,
|
|
387
|
+
dummyLength,
|
|
388
|
+
dummyData,
|
|
389
|
+
as,
|
|
390
|
+
children
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
function MasterShimmer({
|
|
395
|
+
id,
|
|
396
|
+
loading,
|
|
397
|
+
config,
|
|
398
|
+
children,
|
|
399
|
+
dummyLength,
|
|
400
|
+
dummyData,
|
|
401
|
+
as,
|
|
402
|
+
className,
|
|
403
|
+
style
|
|
404
|
+
}) {
|
|
405
|
+
const containerRef = React2.useRef(null);
|
|
406
|
+
const [reporterRects, setReporterRects] = React2.useState({});
|
|
407
|
+
const register = React2.useCallback((rid, rects) => {
|
|
408
|
+
setReporterRects((prev) => ({ ...prev, [rid]: rects }));
|
|
409
|
+
}, []);
|
|
410
|
+
const unregister = React2.useCallback((rid) => {
|
|
411
|
+
setReporterRects((prev) => {
|
|
412
|
+
const next = { ...prev };
|
|
413
|
+
delete next[rid];
|
|
414
|
+
return next;
|
|
415
|
+
});
|
|
416
|
+
}, []);
|
|
417
|
+
React2__default.default.useEffect(() => {
|
|
418
|
+
injectStyles();
|
|
419
|
+
}, []);
|
|
420
|
+
const tracedRects = useTrace(
|
|
421
|
+
containerRef,
|
|
422
|
+
loading,
|
|
423
|
+
config.borderRadius || void 0
|
|
424
|
+
);
|
|
425
|
+
const allRects = React2.useMemo(() => {
|
|
426
|
+
const reported = Object.values(reporterRects).flat();
|
|
427
|
+
return [...tracedRects, ...reported];
|
|
428
|
+
}, [tracedRects, reporterRects]);
|
|
429
|
+
const renderedChildren = useSkeletonChildren({
|
|
430
|
+
loading,
|
|
431
|
+
children,
|
|
432
|
+
dummyLength,
|
|
433
|
+
dummyData,
|
|
434
|
+
as,
|
|
435
|
+
id
|
|
436
|
+
});
|
|
437
|
+
const contextValue = React2.useMemo(
|
|
438
|
+
() => ({
|
|
439
|
+
register,
|
|
440
|
+
unregister,
|
|
441
|
+
masterRef: containerRef,
|
|
442
|
+
loading,
|
|
443
|
+
config
|
|
444
|
+
}),
|
|
445
|
+
[register, unregister, loading, config]
|
|
446
|
+
);
|
|
447
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ShimmerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
448
|
+
"div",
|
|
449
|
+
{
|
|
450
|
+
ref: containerRef,
|
|
451
|
+
className,
|
|
452
|
+
style: {
|
|
453
|
+
position: "relative",
|
|
454
|
+
visibility: loading && !config.preserveBackground ? "hidden" : void 0,
|
|
455
|
+
...style
|
|
456
|
+
},
|
|
457
|
+
"aria-hidden": loading || void 0,
|
|
458
|
+
"data-shimmer-master": true,
|
|
459
|
+
"data-shimmer-preserve-bg": loading && config.preserveBackground ? "true" : void 0,
|
|
460
|
+
children: [
|
|
461
|
+
renderedChildren,
|
|
462
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx(
|
|
463
|
+
ShimmerOverlay,
|
|
464
|
+
{
|
|
465
|
+
rects: allRects,
|
|
466
|
+
animation: config.animation,
|
|
467
|
+
baseColor: config.baseColor,
|
|
468
|
+
highlightColor: config.highlightColor,
|
|
469
|
+
speed: config.speed
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
) });
|
|
475
|
+
}
|
|
476
|
+
function ReporterShimmer({
|
|
477
|
+
id,
|
|
478
|
+
parentContext,
|
|
479
|
+
config,
|
|
480
|
+
children,
|
|
481
|
+
dummyLength,
|
|
482
|
+
dummyData,
|
|
483
|
+
as
|
|
484
|
+
}) {
|
|
485
|
+
const containerRef = React2.useRef(null);
|
|
486
|
+
const tracedRects = useTrace(
|
|
487
|
+
containerRef,
|
|
488
|
+
parentContext.loading,
|
|
489
|
+
config.borderRadius || void 0,
|
|
490
|
+
parentContext.masterRef
|
|
491
|
+
);
|
|
492
|
+
React2__default.default.useLayoutEffect(() => {
|
|
493
|
+
if (!parentContext.loading || tracedRects.length === 0) {
|
|
494
|
+
parentContext.unregister(id);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
parentContext.register(id, tracedRects);
|
|
498
|
+
return () => {
|
|
499
|
+
parentContext.unregister(id);
|
|
500
|
+
};
|
|
501
|
+
}, [tracedRects, parentContext, id]);
|
|
502
|
+
const renderedChildren = useSkeletonChildren({
|
|
503
|
+
loading: parentContext.loading,
|
|
504
|
+
children,
|
|
505
|
+
dummyLength,
|
|
506
|
+
dummyData,
|
|
507
|
+
as,
|
|
508
|
+
id
|
|
509
|
+
});
|
|
510
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
511
|
+
"div",
|
|
512
|
+
{
|
|
513
|
+
ref: containerRef,
|
|
514
|
+
"data-shimmer-reporter": true,
|
|
515
|
+
style: { display: "contents" },
|
|
516
|
+
children: renderedChildren
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
function useSkeletonChildren({
|
|
521
|
+
loading,
|
|
522
|
+
children,
|
|
523
|
+
dummyLength,
|
|
524
|
+
dummyData,
|
|
525
|
+
as,
|
|
526
|
+
id
|
|
527
|
+
}) {
|
|
528
|
+
if (!loading) return children;
|
|
529
|
+
if (as) {
|
|
530
|
+
const count = dummyLength && dummyLength > 0 ? dummyLength : 1;
|
|
531
|
+
const Component = as;
|
|
532
|
+
return Array.from({ length: count }, (_, i) => /* @__PURE__ */ React2.createElement(
|
|
533
|
+
Component,
|
|
534
|
+
{
|
|
535
|
+
...dummyData || {},
|
|
536
|
+
key: generateShimmerKey(`${id}-as-${i}`)
|
|
537
|
+
}
|
|
538
|
+
));
|
|
539
|
+
}
|
|
540
|
+
const childArray = React2__default.default.Children.toArray(children);
|
|
541
|
+
const templated = childArray.map((c, i) => {
|
|
542
|
+
if (!React2__default.default.isValidElement(c)) return c;
|
|
543
|
+
const key = generateShimmerKey(`${id}-tpl-${i}`);
|
|
544
|
+
const props = dummyData ? { ...dummyData, key } : { key };
|
|
545
|
+
return React2__default.default.cloneElement(c, props);
|
|
546
|
+
});
|
|
547
|
+
if (dummyLength && dummyLength > 0) {
|
|
548
|
+
const first = templated.find((c) => React2__default.default.isValidElement(c));
|
|
549
|
+
if (!first) return null;
|
|
550
|
+
return Array.from(
|
|
551
|
+
{ length: dummyLength },
|
|
552
|
+
(_, i) => React2__default.default.cloneElement(first, {
|
|
553
|
+
key: generateShimmerKey(`${id}-clone-${i}`)
|
|
554
|
+
})
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
return templated;
|
|
558
|
+
}
|
|
559
|
+
function createShimmer(config = {}) {
|
|
560
|
+
const mergedConfig = {
|
|
561
|
+
animation: config.animation ?? DEFAULTS.animation,
|
|
562
|
+
baseColor: config.baseColor ?? DEFAULTS.baseColor,
|
|
563
|
+
highlightColor: config.highlightColor ?? DEFAULTS.highlightColor,
|
|
564
|
+
speed: config.speed ?? DEFAULTS.speed,
|
|
565
|
+
borderRadius: config.borderRadius ?? DEFAULTS.borderRadius,
|
|
566
|
+
preserveBackground: config.preserveBackground ?? DEFAULTS.preserveBackground
|
|
567
|
+
};
|
|
568
|
+
function ConfiguredShimmer(props) {
|
|
569
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
570
|
+
Shimmer,
|
|
571
|
+
{
|
|
572
|
+
...mergedConfig,
|
|
573
|
+
...props
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
return ConfiguredShimmer;
|
|
578
|
+
}
|
|
579
|
+
function ShimmerSuspense({
|
|
580
|
+
children,
|
|
581
|
+
template,
|
|
582
|
+
...shimmerConfig
|
|
583
|
+
}) {
|
|
584
|
+
const skeletonContent = template !== void 0 ? template : /* @__PURE__ */ jsxRuntime.jsx(IsShimmeringContext.Provider, { value: true, children });
|
|
585
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
586
|
+
React2__default.default.Suspense,
|
|
587
|
+
{
|
|
588
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { loading: true, ...shimmerConfig, children: skeletonContent }),
|
|
589
|
+
children
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
exports.Shimmer = Shimmer;
|
|
595
|
+
exports.ShimmerContext = ShimmerContext;
|
|
596
|
+
exports.ShimmerSuspense = ShimmerSuspense;
|
|
597
|
+
exports.createShimmer = createShimmer;
|
|
598
|
+
exports.useIsShimmering = useIsShimmering;
|
|
599
|
+
exports.useShimmerContext = useShimmerContext;
|
|
600
|
+
//# sourceMappingURL=index.js.map
|
|
601
|
+
//# sourceMappingURL=index.js.map
|