shimmer-from-structure 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,11 +7,13 @@ A React shimmer/skeleton library that **automatically adapts to your component's
7
7
  ## Why This Library?
8
8
 
9
9
  Traditional shimmer libraries require you to:
10
+
10
11
  - Manually create skeleton components that mirror your real components
11
12
  - Maintain two versions of each component (real + skeleton)
12
13
  - Update skeletons every time your layout changes
13
14
 
14
15
  **Shimmer From Structure** eliminates all of that:
16
+
15
17
  - ✅ Automatically measures your component's structure at runtime
16
18
  - ✅ Generates shimmer effects that match actual dimensions
17
19
  - ✅ Zero maintenance - works with any layout changes
@@ -80,10 +82,7 @@ function App() {
80
82
  const [user, setUser] = useState(null);
81
83
 
82
84
  return (
83
- <Shimmer
84
- loading={loading}
85
- templateProps={{ user: userTemplate }}
86
- >
85
+ <Shimmer loading={loading} templateProps={{ user: userTemplate }}>
87
86
  <UserCard user={user || userTemplate} />
88
87
  </Shimmer>
89
88
  );
@@ -96,15 +95,15 @@ The `templateProps` object is spread onto the first child component when loading
96
95
 
97
96
  ### `<Shimmer>` Props
98
97
 
99
- | Prop | Type | Default | Description |
100
- |------|------|---------|-------------|
101
- | `loading` | `boolean` | `true` | Whether to show shimmer effect or actual content |
102
- | `children` | `React.ReactNode` | required | The content to render/measure |
103
- | `shimmerColor` | `string` | `'rgba(255,255,255,0.15)'` | Color of the shimmer wave |
104
- | `backgroundColor` | `string` | `'rgba(255,255,255,0.08)'` | Background color of shimmer blocks |
105
- | `duration` | `number` | `1.5` | Animation duration in seconds |
106
- | `fallbackBorderRadius` | `number` | `4` | Border radius (px) for elements with no CSS border-radius |
107
- | `templateProps` | `Record<string, unknown>` | - | Props to inject into first child for skeleton rendering |
98
+ | Prop | Type | Default | Description |
99
+ | ---------------------- | ------------------------- | -------------------------- | --------------------------------------------------------- |
100
+ | `loading` | `boolean` | `true` | Whether to show shimmer effect or actual content |
101
+ | `children` | `React.ReactNode` | required | The content to render/measure |
102
+ | `shimmerColor` | `string` | `'rgba(255,255,255,0.15)'` | Color of the shimmer wave |
103
+ | `backgroundColor` | `string` | `'rgba(255,255,255,0.08)'` | Background color of shimmer blocks |
104
+ | `duration` | `number` | `1.5` | Animation duration in seconds |
105
+ | `fallbackBorderRadius` | `number` | `4` | Border radius (px) for elements with no CSS border-radius |
106
+ | `templateProps` | `Record<string, unknown>` | - | Props to inject into first child for skeleton rendering |
108
107
 
109
108
  ### Example with All Props
110
109
 
@@ -115,9 +114,9 @@ The `templateProps` object is spread onto the first child component when loading
115
114
  backgroundColor="rgba(255, 255, 255, 0.1)"
116
115
  duration={2}
117
116
  fallbackBorderRadius={8}
118
- templateProps={{
117
+ templateProps={{
119
118
  user: userTemplate,
120
- settings: settingsTemplate
119
+ settings: settingsTemplate,
121
120
  }}
122
121
  >
123
122
  <MyComponent user={user} settings={settings} />
@@ -150,17 +149,17 @@ Each section can have its own independent loading state:
150
149
  function Dashboard() {
151
150
  const [loadingUser, setLoadingUser] = useState(true);
152
151
  const [loadingStats, setLoadingStats] = useState(true);
153
-
152
+
154
153
  return (
155
154
  <>
156
155
  {/* User profile section */}
157
156
  <Shimmer loading={loadingUser} templateProps={{ user: userTemplate }}>
158
157
  <UserProfile user={user} />
159
158
  </Shimmer>
160
-
159
+
161
160
  {/* Stats section - with custom colors */}
162
- <Shimmer
163
- loading={loadingStats}
161
+ <Shimmer
162
+ loading={loadingStats}
164
163
  templateProps={{ stats: statsTemplate }}
165
164
  shimmerColor="rgba(20, 184, 166, 0.2)"
166
165
  >
@@ -174,10 +173,7 @@ function Dashboard() {
174
173
  ### Transactions List
175
174
 
176
175
  ```tsx
177
- <Shimmer
178
- loading={loadingTransactions}
179
- templateProps={{ transactions: transactionsTemplate }}
180
- >
176
+ <Shimmer loading={loadingTransactions} templateProps={{ transactions: transactionsTemplate }}>
181
177
  <TransactionsList transactions={transactions} />
182
178
  </Shimmer>
183
179
  ```
@@ -190,15 +186,119 @@ function Dashboard() {
190
186
  </Shimmer>
191
187
  ```
192
188
 
189
+ ## 🔄 Using with React Suspense
190
+
191
+ Shimmer works seamlessly as a Suspense fallback. When used this way, `loading` is always `true` because React automatically unmounts the fallback and replaces it with the resolved component.
192
+
193
+ ### Basic Suspense Pattern
194
+
195
+ ```tsx
196
+ import { Suspense, lazy } from 'react';
197
+ import { Shimmer } from 'shimmer-from-structure';
198
+
199
+ const UserProfile = lazy(() => import('./UserProfile'));
200
+
201
+ function App() {
202
+ return (
203
+ <Suspense
204
+ fallback={
205
+ <Shimmer loading={true} templateProps={{ user: userTemplate }}>
206
+ <UserProfile />
207
+ </Shimmer>
208
+ }
209
+ >
210
+ <UserProfile userId="123" />
211
+ </Suspense>
212
+ );
213
+ }
214
+ ```
215
+
216
+ ### Why `loading={true}` is Always Set
217
+
218
+ When using Shimmer as a Suspense fallback:
219
+
220
+ 1. **Suspend**: React renders the fallback → Shimmer shows with `loading={true}`
221
+ 2. **Resolve**: React **replaces** the entire fallback with the real component
222
+ 3. The Shimmer is **unmounted**, not updated — so you never need to toggle `loading`
223
+
224
+ ### Performance Tips for Suspense
225
+
226
+ **Memoize the fallback** to prevent re-renders:
227
+
228
+ ```tsx
229
+ const ShimmerFallback = React.memo(() => (
230
+ <Shimmer loading={true} templateProps={{ user: userTemplate }}>
231
+ <UserProfile />
232
+ </Shimmer>
233
+ ));
234
+
235
+ // Usage
236
+ <Suspense fallback={<ShimmerFallback />}>
237
+ <UserProfile userId="123" />
238
+ </Suspense>;
239
+ ```
240
+
241
+ **Keep templates lightweight** — the DOM is measured synchronously via `useLayoutEffect`, so avoid complex logic in your template.
242
+
243
+ ## Global Configuration (Context API)
244
+
245
+ You can set default configuration for your entire app (or specific sections) using `ShimmerProvider`. This is perfect for maintaining consistent themes without repeating props.
246
+
247
+ ```tsx
248
+ import { Shimmer, ShimmerProvider } from 'shimmer-from-structure';
249
+
250
+ function App() {
251
+ return (
252
+ // Set global defaults
253
+ <ShimmerProvider
254
+ config={{
255
+ shimmerColor: 'rgba(56, 189, 248, 0.4)', // Blue shimmer
256
+ backgroundColor: 'rgba(56, 189, 248, 0.1)', // Blue background
257
+ duration: 2.5,
258
+ fallbackBorderRadius: 8,
259
+ }}
260
+ >
261
+ <Dashboard />
262
+ </ShimmerProvider>
263
+ );
264
+ }
265
+ ```
266
+
267
+ Components inside the provider automatically inherit values. You can still override them locally:
268
+
269
+ ```tsx
270
+ // Inherits blue theme from provider
271
+ <Shimmer loading={true}><UserCard /></Shimmer>
272
+
273
+ // Overrides provider settings
274
+ <Shimmer loading={true} duration={0.5}><FastCard /></Shimmer>
275
+ ```
276
+
277
+ ### Accessing Config in Hooks
278
+
279
+ If you need to access the current configuration in your own components:
280
+
281
+ ```tsx
282
+ import { useShimmerConfig } from 'shimmer-from-structure';
283
+
284
+ function MyComponent() {
285
+ const config = useShimmerConfig();
286
+ return <div style={{ background: config.backgroundColor }}>...</div>;
287
+ }
288
+ ```
289
+
193
290
  ## Best Practices
194
291
 
195
292
  ### 1. Use `templateProps` for Dynamic Data
293
+
196
294
  When your component receives data via props, always provide `templateProps` with mock data that matches the expected structure.
197
295
 
198
296
  ### 2. Match Template Structure to Real Data
297
+
199
298
  Ensure your template data has the same array length and property structure as real data for accurate shimmer layout.
200
299
 
201
300
  ### 3. Use Individual Shimmer Components
301
+
202
302
  Wrap each section in its own Shimmer for independent loading states:
203
303
 
204
304
  ```tsx
@@ -214,7 +314,9 @@ Wrap each section in its own Shimmer for independent loading states:
214
314
  ```
215
315
 
216
316
  ### 4. Consider Element Widths
317
+
217
318
  Block elements like `<h1>`, `<p>` take full container width. If you want shimmer to match text width:
319
+
218
320
  ```css
219
321
  .title {
220
322
  width: fit-content;
@@ -222,6 +324,7 @@ Block elements like `<h1>`, `<p>` take full container width. If you want shimmer
222
324
  ```
223
325
 
224
326
  ### 5. Provide Container Dimensions
327
+
225
328
  For async components (like charts), ensure containers have explicit dimensions so shimmer has something to measure.
226
329
 
227
330
  ## ⚡ Performance Considerations
@@ -231,6 +334,22 @@ For async components (like charts), ensure containers have explicit dimensions s
231
334
  - Minimal re-renders - only updates when loading state or children change
232
335
  - Lightweight DOM measurements using native browser APIs
233
336
 
337
+ ### 6. Tables and Merged Shimmers
338
+
339
+ For tables, the library measures the entire cell (`<td>` or `<th>`), including padding. This can cause adjacent shimmer blocks to touch and merge visually. To prevent this:
340
+
341
+ Wrap the text content of your cells in `<span>` tags. The library will then measure the `<span>`, treating the cell padding as whitespace.
342
+
343
+ ```tsx
344
+ // ❌ Padded cell causes merging
345
+ <td style={{ padding: '16px' }}>Content</td>
346
+
347
+ // ✅ Wrapped content preserves spacing
348
+ <td style={{ padding: '16px' }}>
349
+ <span>Content</span>
350
+ </td>
351
+ ```
352
+
234
353
  ## 🛠️ Development
235
354
 
236
355
  ```bash
@@ -0,0 +1,51 @@
1
+ import { default as React, ReactNode } from 'react';
2
+ /**
3
+ * Configuration options for shimmer appearance and behavior.
4
+ * All properties are optional when providing config to ShimmerProvider.
5
+ */
6
+ export interface ShimmerConfig {
7
+ /** Color of the shimmer wave animation */
8
+ shimmerColor?: string;
9
+ /** Background color of shimmer placeholders */
10
+ backgroundColor?: string;
11
+ /** Duration of one shimmer animation cycle in seconds */
12
+ duration?: number;
13
+ /** Fallback border radius (px) for elements without explicit border-radius */
14
+ fallbackBorderRadius?: number;
15
+ }
16
+ /**
17
+ * Internal context value type with all required properties.
18
+ * Ensures consuming components always receive valid values.
19
+ */
20
+ interface ShimmerContextValue {
21
+ shimmerColor: string;
22
+ backgroundColor: string;
23
+ duration: number;
24
+ fallbackBorderRadius: number;
25
+ }
26
+ /** Default configuration values */
27
+ declare const defaultConfig: ShimmerContextValue;
28
+ export interface ShimmerProviderProps {
29
+ /** Shimmer configuration to apply to all child Shimmer components */
30
+ config?: ShimmerConfig;
31
+ children: ReactNode;
32
+ }
33
+ /**
34
+ * Provider component for global shimmer configuration.
35
+ * Wrap your app or a section of your component tree to apply default shimmer settings.
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <ShimmerProvider config={{ shimmerColor: '#fff', duration: 2 }}>
40
+ * <App />
41
+ * </ShimmerProvider>
42
+ * ```
43
+ */
44
+ export declare const ShimmerProvider: React.FC<ShimmerProviderProps>;
45
+ /**
46
+ * Hook to access the current shimmer configuration from context.
47
+ * Returns default values if no ShimmerProvider is present.
48
+ * All returned values are guaranteed to be defined.
49
+ */
50
+ export declare const useShimmerConfig: () => ShimmerContextValue;
51
+ export { defaultConfig as shimmerDefaults };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { Shimmer } from './Shimmer';
2
- export type { ShimmerProps, ElementInfo } from './types';
2
+ export type { ShimmerProps, ElementInfo, ShimmerConfig } from './types';
3
+ export { ShimmerProvider, useShimmerConfig } from './ShimmerContext';
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
- import y, { useState as te, useRef as M, useLayoutEffect as ne } from "react";
2
- var N = { exports: {} }, _ = {};
1
+ import T, { createContext as ne, useMemo as ae, useContext as se, useState as ie, useRef as z, useLayoutEffect as le } from "react";
2
+ var L = { exports: {} }, g = {};
3
3
  /**
4
4
  * @license React
5
5
  * react-jsx-runtime.production.js
@@ -9,29 +9,29 @@ var N = { exports: {} }, _ = {};
9
9
  * This source code is licensed under the MIT license found in the
10
10
  * LICENSE file in the root directory of this source tree.
11
11
  */
12
- var W;
13
- function oe() {
14
- if (W) return _;
15
- W = 1;
12
+ var X;
13
+ function ue() {
14
+ if (X) return g;
15
+ X = 1;
16
16
  var t = Symbol.for("react.transitional.element"), s = Symbol.for("react.fragment");
17
- function f(u, i, c) {
17
+ function l(u, i, f) {
18
18
  var d = null;
19
- if (c !== void 0 && (d = "" + c), i.key !== void 0 && (d = "" + i.key), "key" in i) {
20
- c = {};
21
- for (var p in i)
22
- p !== "key" && (c[p] = i[p]);
23
- } else c = i;
24
- return i = c.ref, {
19
+ if (f !== void 0 && (d = "" + f), i.key !== void 0 && (d = "" + i.key), "key" in i) {
20
+ f = {};
21
+ for (var m in i)
22
+ m !== "key" && (f[m] = i[m]);
23
+ } else f = i;
24
+ return i = f.ref, {
25
25
  $$typeof: t,
26
26
  type: u,
27
27
  key: d,
28
28
  ref: i !== void 0 ? i : null,
29
- props: c
29
+ props: f
30
30
  };
31
31
  }
32
- return _.Fragment = s, _.jsx = f, _.jsxs = f, _;
32
+ return g.Fragment = s, g.jsx = l, g.jsxs = l, g;
33
33
  }
34
- var T = {};
34
+ var k = {};
35
35
  /**
36
36
  * @license React
37
37
  * react-jsx-runtime.development.js
@@ -41,44 +41,44 @@ var T = {};
41
41
  * This source code is licensed under the MIT license found in the
42
42
  * LICENSE file in the root directory of this source tree.
43
43
  */
44
- var U;
45
- function ae() {
46
- return U || (U = 1, process.env.NODE_ENV !== "production" && function() {
44
+ var G;
45
+ function ce() {
46
+ return G || (G = 1, process.env.NODE_ENV !== "production" && function() {
47
47
  function t(e) {
48
48
  if (e == null) return null;
49
49
  if (typeof e == "function")
50
- return e.$$typeof === K ? null : e.displayName || e.name || null;
50
+ return e.$$typeof === re ? null : e.displayName || e.name || null;
51
51
  if (typeof e == "string") return e;
52
52
  switch (e) {
53
- case A:
53
+ case p:
54
54
  return "Fragment";
55
- case X:
55
+ case b:
56
56
  return "Profiler";
57
- case z:
57
+ case c:
58
58
  return "StrictMode";
59
- case B:
59
+ case Z:
60
60
  return "Suspense";
61
- case H:
62
- return "SuspenseList";
63
61
  case Q:
62
+ return "SuspenseList";
63
+ case ee:
64
64
  return "Activity";
65
65
  }
66
66
  if (typeof e == "object")
67
67
  switch (typeof e.tag == "number" && console.error(
68
68
  "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
69
69
  ), e.$$typeof) {
70
- case k:
70
+ case R:
71
71
  return "Portal";
72
- case J:
72
+ case P:
73
73
  return e.displayName || "Context";
74
- case G:
74
+ case _:
75
75
  return (e._context.displayName || "Context") + ".Consumer";
76
- case q:
76
+ case H:
77
77
  var r = e.render;
78
78
  return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
79
- case Z:
79
+ case K:
80
80
  return r = e.displayName || null, r !== null ? r : t(e.type) || "Memo";
81
- case S:
81
+ case N:
82
82
  r = e._payload, e = e._init;
83
83
  try {
84
84
  return t(e(r));
@@ -90,7 +90,7 @@ function ae() {
90
90
  function s(e) {
91
91
  return "" + e;
92
92
  }
93
- function f(e) {
93
+ function l(e) {
94
94
  try {
95
95
  s(e);
96
96
  var r = !1;
@@ -99,17 +99,17 @@ function ae() {
99
99
  }
100
100
  if (r) {
101
101
  r = console;
102
- var n = r.error, o = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
103
- return n.call(
102
+ var o = r.error, n = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
103
+ return o.call(
104
104
  r,
105
105
  "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
106
- o
106
+ n
107
107
  ), s(e);
108
108
  }
109
109
  }
110
110
  function u(e) {
111
- if (e === A) return "<>";
112
- if (typeof e == "object" && e !== null && e.$$typeof === S)
111
+ if (e === p) return "<>";
112
+ if (typeof e == "object" && e !== null && e.$$typeof === N)
113
113
  return "<...>";
114
114
  try {
115
115
  var r = t(e);
@@ -119,48 +119,48 @@ function ae() {
119
119
  }
120
120
  }
121
121
  function i() {
122
- var e = j.A;
122
+ var e = $.A;
123
123
  return e === null ? null : e.getOwner();
124
124
  }
125
- function c() {
125
+ function f() {
126
126
  return Error("react-stack-top-frame");
127
127
  }
128
128
  function d(e) {
129
- if ($.call(e, "key")) {
129
+ if (D.call(e, "key")) {
130
130
  var r = Object.getOwnPropertyDescriptor(e, "key").get;
131
131
  if (r && r.isReactWarning) return !1;
132
132
  }
133
133
  return e.key !== void 0;
134
134
  }
135
- function p(e, r) {
136
- function n() {
137
- Y || (Y = !0, console.error(
135
+ function m(e, r) {
136
+ function o() {
137
+ B || (B = !0, console.error(
138
138
  "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
139
139
  r
140
140
  ));
141
141
  }
142
- n.isReactWarning = !0, Object.defineProperty(e, "key", {
143
- get: n,
142
+ o.isReactWarning = !0, Object.defineProperty(e, "key", {
143
+ get: o,
144
144
  configurable: !0
145
145
  });
146
146
  }
147
- function x() {
147
+ function j() {
148
148
  var e = t(this.type);
149
- return I[e] || (I[e] = !0, console.error(
149
+ return M[e] || (M[e] = !0, console.error(
150
150
  "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
151
151
  )), e = this.props.ref, e !== void 0 ? e : null;
152
152
  }
153
- function w(e, r, n, o, g, P) {
154
- var a = n.ref;
153
+ function O(e, r, o, n, A, I) {
154
+ var a = o.ref;
155
155
  return e = {
156
- $$typeof: b,
156
+ $$typeof: S,
157
157
  type: e,
158
158
  key: r,
159
- props: n,
160
- _owner: o
159
+ props: o,
160
+ _owner: n
161
161
  }, (a !== void 0 ? a : null) !== null ? Object.defineProperty(e, "ref", {
162
162
  enumerable: !1,
163
- get: x
163
+ get: j
164
164
  }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
165
165
  configurable: !1,
166
166
  enumerable: !1,
@@ -175,157 +175,174 @@ function ae() {
175
175
  configurable: !1,
176
176
  enumerable: !1,
177
177
  writable: !0,
178
- value: g
178
+ value: A
179
179
  }), Object.defineProperty(e, "_debugTask", {
180
180
  configurable: !1,
181
181
  enumerable: !1,
182
182
  writable: !0,
183
- value: P
183
+ value: I
184
184
  }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
185
185
  }
186
- function h(e, r, n, o, g, P) {
186
+ function x(e, r, o, n, A, I) {
187
187
  var a = r.children;
188
188
  if (a !== void 0)
189
- if (o)
190
- if (ee(a)) {
191
- for (o = 0; o < a.length; o++)
192
- R(a[o]);
189
+ if (n)
190
+ if (te(a)) {
191
+ for (n = 0; n < a.length; n++)
192
+ C(a[n]);
193
193
  Object.freeze && Object.freeze(a);
194
194
  } else
195
195
  console.error(
196
196
  "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
197
197
  );
198
- else R(a);
199
- if ($.call(r, "key")) {
198
+ else C(a);
199
+ if (D.call(r, "key")) {
200
200
  a = t(e);
201
- var v = Object.keys(r).filter(function(re) {
202
- return re !== "key";
201
+ var v = Object.keys(r).filter(function(oe) {
202
+ return oe !== "key";
203
203
  });
204
- o = 0 < v.length ? "{key: someKey, " + v.join(": ..., ") + ": ...}" : "{key: someKey}", D[a + o] || (v = 0 < v.length ? "{" + v.join(": ..., ") + ": ...}" : "{}", console.error(
204
+ n = 0 < v.length ? "{key: someKey, " + v.join(": ..., ") + ": ...}" : "{key: someKey}", V[a + n] || (v = 0 < v.length ? "{" + v.join(": ..., ") + ": ...}" : "{}", console.error(
205
205
  `A props object containing a "key" prop is being spread into JSX:
206
206
  let props = %s;
207
207
  <%s {...props} />
208
208
  React keys must be passed directly to JSX without using spread:
209
209
  let props = %s;
210
210
  <%s key={someKey} {...props} />`,
211
- o,
211
+ n,
212
212
  a,
213
213
  v,
214
214
  a
215
- ), D[a + o] = !0);
215
+ ), V[a + n] = !0);
216
216
  }
217
- if (a = null, n !== void 0 && (f(n), a = "" + n), d(r) && (f(r.key), a = "" + r.key), "key" in r) {
218
- n = {};
219
- for (var C in r)
220
- C !== "key" && (n[C] = r[C]);
221
- } else n = r;
222
- return a && p(
223
- n,
217
+ if (a = null, o !== void 0 && (l(o), a = "" + o), d(r) && (l(r.key), a = "" + r.key), "key" in r) {
218
+ o = {};
219
+ for (var F in r)
220
+ F !== "key" && (o[F] = r[F]);
221
+ } else o = r;
222
+ return a && m(
223
+ o,
224
224
  typeof e == "function" ? e.displayName || e.name || "Unknown" : e
225
- ), w(
225
+ ), O(
226
226
  e,
227
227
  a,
228
- n,
228
+ o,
229
229
  i(),
230
- g,
231
- P
230
+ A,
231
+ I
232
232
  );
233
233
  }
234
- function R(e) {
235
- l(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === S && (e._payload.status === "fulfilled" ? l(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
234
+ function C(e) {
235
+ w(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === N && (e._payload.status === "fulfilled" ? w(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
236
236
  }
237
- function l(e) {
238
- return typeof e == "object" && e !== null && e.$$typeof === b;
237
+ function w(e) {
238
+ return typeof e == "object" && e !== null && e.$$typeof === S;
239
239
  }
240
- var m = y, b = Symbol.for("react.transitional.element"), k = Symbol.for("react.portal"), A = Symbol.for("react.fragment"), z = Symbol.for("react.strict_mode"), X = Symbol.for("react.profiler"), G = Symbol.for("react.consumer"), J = Symbol.for("react.context"), q = Symbol.for("react.forward_ref"), B = Symbol.for("react.suspense"), H = Symbol.for("react.suspense_list"), Z = Symbol.for("react.memo"), S = Symbol.for("react.lazy"), Q = Symbol.for("react.activity"), K = Symbol.for("react.client.reference"), j = m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, $ = Object.prototype.hasOwnProperty, ee = Array.isArray, O = console.createTask ? console.createTask : function() {
240
+ var E = T, S = Symbol.for("react.transitional.element"), R = Symbol.for("react.portal"), p = Symbol.for("react.fragment"), c = Symbol.for("react.strict_mode"), b = Symbol.for("react.profiler"), _ = Symbol.for("react.consumer"), P = Symbol.for("react.context"), H = Symbol.for("react.forward_ref"), Z = Symbol.for("react.suspense"), Q = Symbol.for("react.suspense_list"), K = Symbol.for("react.memo"), N = Symbol.for("react.lazy"), ee = Symbol.for("react.activity"), re = Symbol.for("react.client.reference"), $ = E.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, D = Object.prototype.hasOwnProperty, te = Array.isArray, Y = console.createTask ? console.createTask : function() {
241
241
  return null;
242
242
  };
243
- m = {
243
+ E = {
244
244
  react_stack_bottom_frame: function(e) {
245
245
  return e();
246
246
  }
247
247
  };
248
- var Y, I = {}, F = m.react_stack_bottom_frame.bind(
249
- m,
250
- c
251
- )(), L = O(u(c)), D = {};
252
- T.Fragment = A, T.jsx = function(e, r, n) {
253
- var o = 1e4 > j.recentlyCreatedOwnerStacks++;
254
- return h(
248
+ var B, M = {}, W = E.react_stack_bottom_frame.bind(
249
+ E,
250
+ f
251
+ )(), U = Y(u(f)), V = {};
252
+ k.Fragment = p, k.jsx = function(e, r, o) {
253
+ var n = 1e4 > $.recentlyCreatedOwnerStacks++;
254
+ return x(
255
255
  e,
256
256
  r,
257
- n,
257
+ o,
258
258
  !1,
259
- o ? Error("react-stack-top-frame") : F,
260
- o ? O(u(e)) : L
259
+ n ? Error("react-stack-top-frame") : W,
260
+ n ? Y(u(e)) : U
261
261
  );
262
- }, T.jsxs = function(e, r, n) {
263
- var o = 1e4 > j.recentlyCreatedOwnerStacks++;
264
- return h(
262
+ }, k.jsxs = function(e, r, o) {
263
+ var n = 1e4 > $.recentlyCreatedOwnerStacks++;
264
+ return x(
265
265
  e,
266
266
  r,
267
- n,
267
+ o,
268
268
  !0,
269
- o ? Error("react-stack-top-frame") : F,
270
- o ? O(u(e)) : L
269
+ n ? Error("react-stack-top-frame") : W,
270
+ n ? Y(u(e)) : U
271
271
  );
272
272
  };
273
- }()), T;
273
+ }()), k;
274
274
  }
275
- process.env.NODE_ENV === "production" ? N.exports = oe() : N.exports = ae();
276
- var E = N.exports;
277
- function se(t) {
275
+ process.env.NODE_ENV === "production" ? L.exports = ue() : L.exports = ce();
276
+ var h = L.exports;
277
+ const y = {
278
+ shimmerColor: "rgba(255, 255, 255, 0.15)",
279
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
280
+ duration: 1.5,
281
+ fallbackBorderRadius: 4
282
+ }, J = ne(y), he = ({
283
+ config: t = {},
284
+ children: s
285
+ }) => {
286
+ const l = ae(() => ({
287
+ shimmerColor: t.shimmerColor ?? y.shimmerColor,
288
+ backgroundColor: t.backgroundColor ?? y.backgroundColor,
289
+ duration: t.duration ?? y.duration,
290
+ fallbackBorderRadius: t.fallbackBorderRadius ?? y.fallbackBorderRadius
291
+ }), [t.shimmerColor, t.backgroundColor, t.duration, t.fallbackBorderRadius]);
292
+ return /* @__PURE__ */ h.jsx(J.Provider, { value: l, children: s });
293
+ }, fe = () => se(J);
294
+ function de(t) {
278
295
  const s = t.tagName.toLowerCase();
279
296
  return !!(["img", "svg", "video", "canvas", "iframe", "input", "textarea", "button"].includes(s) || !(Array.from(t.children).length > 0));
280
297
  }
281
- function V(t, s) {
282
- const f = [], u = t.getBoundingClientRect();
298
+ function q(t, s) {
299
+ const l = [], u = t.getBoundingClientRect();
283
300
  if (u.width === 0 || u.height === 0)
284
- return f;
285
- if (se(t)) {
286
- const c = window.getComputedStyle(t).borderRadius || "0px", d = {
301
+ return l;
302
+ if (de(t)) {
303
+ const f = window.getComputedStyle(t).borderRadius || "0px", d = {
287
304
  x: u.left - s.left,
288
305
  y: u.top - s.top,
289
306
  width: u.width,
290
307
  height: u.height,
291
308
  tag: t.tagName.toLowerCase(),
292
- borderRadius: c
309
+ borderRadius: f
293
310
  };
294
- f.push(d);
311
+ l.push(d);
295
312
  } else
296
313
  Array.from(t.children).forEach((i) => {
297
- f.push(...V(i, s));
314
+ l.push(...q(i, s));
298
315
  });
299
- return f;
316
+ return l;
300
317
  }
301
- const le = ({
318
+ const be = ({
302
319
  children: t,
303
320
  loading: s = !0,
304
- shimmerColor: f = "rgba(255, 255, 255, 0.15)",
305
- backgroundColor: u = "rgba(255, 255, 255, 0.08)",
306
- duration: i = 1.5,
307
- fallbackBorderRadius: c = 4,
321
+ shimmerColor: l,
322
+ backgroundColor: u,
323
+ duration: i,
324
+ fallbackBorderRadius: f,
308
325
  templateProps: d
309
326
  }) => {
310
- const [p, x] = te([]), w = M(null), h = M(null), R = y.useMemo(() => {
327
+ const m = fe(), j = l ?? m.shimmerColor, O = u ?? m.backgroundColor, x = i ?? m.duration, C = f ?? m.fallbackBorderRadius, [w, E] = ie([]), S = z(null), R = z(null), p = T.useMemo(() => {
311
328
  if (!s || !d)
312
329
  return t;
313
- const l = y.Children.toArray(t);
314
- if (l.length === 0)
330
+ const c = T.Children.toArray(t);
331
+ if (c.length === 0)
315
332
  return t;
316
- const m = l[0];
317
- return y.isValidElement(m) ? [y.cloneElement(m, {
333
+ const b = c[0];
334
+ return T.isValidElement(b) ? [T.cloneElement(b, {
318
335
  ...d
319
- }), ...l.slice(1)] : t;
336
+ }), ...c.slice(1)] : t;
320
337
  }, [t, s, d]);
321
- return ne(() => {
322
- if (!s || !h.current) return;
323
- const l = h.current, m = l.getBoundingClientRect(), b = [];
324
- Array.from(l.children).forEach((k) => {
325
- b.push(...V(k, m));
326
- }), x(b);
327
- }, [s, R]), s ? /* @__PURE__ */ E.jsxs("div", { style: { position: "relative" }, children: [
328
- /* @__PURE__ */ E.jsx("style", { children: `
338
+ return le(() => {
339
+ if (!s || !R.current) return;
340
+ const c = R.current, b = c.getBoundingClientRect(), _ = [];
341
+ Array.from(c.children).forEach((P) => {
342
+ _.push(...q(P, b));
343
+ }), E(_);
344
+ }, [s, p]), s ? /* @__PURE__ */ h.jsxs("div", { style: { position: "relative" }, children: [
345
+ /* @__PURE__ */ h.jsx("style", { children: `
329
346
  .shimmer-measure-container * {
330
347
  color: transparent !important;
331
348
  border-color: transparent !important;
@@ -336,22 +353,22 @@ const le = ({
336
353
  opacity: 0;
337
354
  }
338
355
  ` }),
339
- /* @__PURE__ */ E.jsx(
356
+ /* @__PURE__ */ h.jsx(
340
357
  "div",
341
358
  {
342
- ref: h,
359
+ ref: R,
343
360
  className: "shimmer-measure-container",
344
361
  style: {
345
362
  pointerEvents: "none"
346
363
  },
347
364
  "aria-hidden": "true",
348
- children: R
365
+ children: p
349
366
  }
350
367
  ),
351
- /* @__PURE__ */ E.jsxs(
368
+ /* @__PURE__ */ h.jsxs(
352
369
  "div",
353
370
  {
354
- ref: w,
371
+ ref: S,
355
372
  style: {
356
373
  position: "absolute",
357
374
  top: 0,
@@ -361,7 +378,7 @@ const le = ({
361
378
  overflow: "hidden"
362
379
  },
363
380
  children: [
364
- /* @__PURE__ */ E.jsx("style", { children: `
381
+ /* @__PURE__ */ h.jsx("style", { children: `
365
382
  @keyframes shimmer {
366
383
  0% {
367
384
  transform: translateX(-100%);
@@ -371,20 +388,20 @@ const le = ({
371
388
  }
372
389
  }
373
390
  ` }),
374
- p.map((l, m) => /* @__PURE__ */ E.jsx(
391
+ w.map((c, b) => /* @__PURE__ */ h.jsx(
375
392
  "div",
376
393
  {
377
394
  style: {
378
395
  position: "absolute",
379
- left: `${l.x}px`,
380
- top: `${l.y}px`,
381
- width: `${l.width}px`,
382
- height: `${l.height}px`,
383
- backgroundColor: u,
384
- borderRadius: l.borderRadius === "0px" ? `${c}px` : l.borderRadius,
396
+ left: `${c.x}px`,
397
+ top: `${c.y}px`,
398
+ width: `${c.width}px`,
399
+ height: `${c.height}px`,
400
+ backgroundColor: O,
401
+ borderRadius: c.borderRadius === "0px" ? `${C}px` : c.borderRadius,
385
402
  overflow: "hidden"
386
403
  },
387
- children: /* @__PURE__ */ E.jsx(
404
+ children: /* @__PURE__ */ h.jsx(
388
405
  "div",
389
406
  {
390
407
  style: {
@@ -393,19 +410,21 @@ const le = ({
393
410
  left: 0,
394
411
  width: "100%",
395
412
  height: "100%",
396
- background: `linear-gradient(90deg, transparent, ${f}, transparent)`,
397
- animation: `shimmer ${i}s infinite`
413
+ background: `linear-gradient(90deg, transparent, ${j}, transparent)`,
414
+ animation: `shimmer ${x}s infinite`
398
415
  }
399
416
  }
400
417
  )
401
418
  },
402
- m
419
+ b
403
420
  ))
404
421
  ]
405
422
  }
406
423
  )
407
- ] }) : /* @__PURE__ */ E.jsx(E.Fragment, { children: t });
424
+ ] }) : /* @__PURE__ */ h.jsx(h.Fragment, { children: t });
408
425
  };
409
426
  export {
410
- le as Shimmer
427
+ be as Shimmer,
428
+ he as ShimmerProvider,
429
+ fe as useShimmerConfig
411
430
  };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(E,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],f):(E=typeof globalThis<"u"?globalThis:E||self,f(E.ShimmerFromStructure={},E.React))})(this,function(E,f){"use strict";var w={exports:{}},y={};/**
1
+ (function(p,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],i):(p=typeof globalThis<"u"?globalThis:p||self,i(p.ShimmerFromStructure={},p.React))})(this,function(p,i){"use strict";var O={exports:{}},g={};/**
2
2
  * @license React
3
3
  * react-jsx-runtime.production.js
4
4
  *
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * This source code is licensed under the MIT license found in the
8
8
  * LICENSE file in the root directory of this source tree.
9
- */var Y;function z(){if(Y)return y;Y=1;var t=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function d(l,i,c){var m=null;if(c!==void 0&&(m=""+c),i.key!==void 0&&(m=""+i.key),"key"in i){c={};for(var b in i)b!=="key"&&(c[b]=i[b])}else c=i;return i=c.ref,{$$typeof:t,type:l,key:m,ref:i!==void 0?i:null,props:c}}return y.Fragment=s,y.jsx=d,y.jsxs=d,y}var T={};/**
9
+ */var M;function Z(){if(M)return g;M=1;var t=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function l(c,u,d){var m=null;if(d!==void 0&&(m=""+d),u.key!==void 0&&(m=""+u.key),"key"in u){d={};for(var b in u)b!=="key"&&(d[b]=u[b])}else d=u;return u=d.ref,{$$typeof:t,type:c,key:m,ref:u!==void 0?u:null,props:d}}return g.Fragment=s,g.jsx=l,g.jsxs=l,g}var k={};/**
10
10
  * @license React
11
11
  * react-jsx-runtime.development.js
12
12
  *
@@ -14,12 +14,12 @@
14
14
  *
15
15
  * This source code is licensed under the MIT license found in the
16
16
  * LICENSE file in the root directory of this source tree.
17
- */var I;function X(){return I||(I=1,process.env.NODE_ENV!=="production"&&function(){function t(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ne?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case j:return"Fragment";case B:return"Profiler";case J:return"StrictMode";case K:return"Suspense";case ee:return"SuspenseList";case te:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case A:return"Portal";case Z:return e.displayName||"Context";case H:return(e._context.displayName||"Context")+".Consumer";case Q:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case re:return r=e.displayName||null,r!==null?r:t(e.type)||"Memo";case O:r=e._payload,e=e._init;try{return t(e(r))}catch{}}return null}function s(e){return""+e}function d(e){try{s(e);var r=!1}catch{r=!0}if(r){r=console;var n=r.error,o=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",o),s(e)}}function l(e){if(e===j)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===O)return"<...>";try{var r=t(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function i(){var e=P.A;return e===null?null:e.getOwner()}function c(){return Error("react-stack-top-frame")}function m(e){if(L.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function b(e,r){function n(){D||(D=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function S(){var e=t(this.type);return M[e]||(M[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function k(e,r,n,o,x,N){var a=n.ref;return e={$$typeof:_,type:e,key:r,props:n,_owner:o},(a!==void 0?a:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:S}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:x}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:N}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function v(e,r,n,o,x,N){var a=r.children;if(a!==void 0)if(o)if(oe(a)){for(o=0;o<a.length;o++)g(a[o]);Object.freeze&&Object.freeze(a)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else g(a);if(L.call(r,"key")){a=t(e);var R=Object.keys(r).filter(function(ae){return ae!=="key"});o=0<R.length?"{key: someKey, "+R.join(": ..., ")+": ...}":"{key: someKey}",V[a+o]||(R=0<R.length?"{"+R.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
17
+ */var B;function Q(){return B||(B=1,process.env.NODE_ENV!=="production"&&function(){function t(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ie?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case _:return"Fragment";case E:return"Profiler";case f:return"StrictMode";case oe:return"Suspense";case ne:return"SuspenseList";case se:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case T:return"Portal";case $:return e.displayName||"Context";case C:return(e._context.displayName||"Context")+".Consumer";case te:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ae:return r=e.displayName||null,r!==null?r:t(e.type)||"Memo";case Y:r=e._payload,e=e._init;try{return t(e(r))}catch{}}return null}function s(e){return""+e}function l(e){try{s(e);var r=!1}catch{r=!0}if(r){r=console;var o=r.error,n=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return o.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n),s(e)}}function c(e){if(e===_)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===Y)return"<...>";try{var r=t(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function u(){var e=I.A;return e===null?null:e.getOwner()}function d(){return Error("react-stack-top-frame")}function m(e){if(z.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function b(e,r){function o(){X||(X=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}o.isReactWarning=!0,Object.defineProperty(e,"key",{get:o,configurable:!0})}function P(){var e=t(this.type);return q[e]||(q[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function N(e,r,o,n,A,L){var a=o.ref;return e={$$typeof:j,type:e,key:r,props:o,_owner:n},(a!==void 0?a:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:P}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:A}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:L}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function x(e,r,o,n,A,L){var a=r.children;if(a!==void 0)if(n)if(ue(a)){for(n=0;n<a.length;n++)S(a[n]);Object.freeze&&Object.freeze(a)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else S(a);if(z.call(r,"key")){a=t(e);var R=Object.keys(r).filter(function(le){return le!=="key"});n=0<R.length?"{key: someKey, "+R.join(": ..., ")+": ...}":"{key: someKey}",H[a+n]||(R=0<R.length?"{"+R.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
18
18
  let props = %s;
19
19
  <%s {...props} />
20
20
  React keys must be passed directly to JSX without using spread:
21
21
  let props = %s;
22
- <%s key={someKey} {...props} />`,o,a,R,a),V[a+o]=!0)}if(a=null,n!==void 0&&(d(n),a=""+n),m(r)&&(d(r.key),a=""+r.key),"key"in r){n={};for(var $ in r)$!=="key"&&(n[$]=r[$])}else n=r;return a&&b(n,typeof e=="function"?e.displayName||e.name||"Unknown":e),k(e,a,n,i(),x,N)}function g(e){u(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===O&&(e._payload.status==="fulfilled"?u(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function u(e){return typeof e=="object"&&e!==null&&e.$$typeof===_}var p=f,_=Symbol.for("react.transitional.element"),A=Symbol.for("react.portal"),j=Symbol.for("react.fragment"),J=Symbol.for("react.strict_mode"),B=Symbol.for("react.profiler"),H=Symbol.for("react.consumer"),Z=Symbol.for("react.context"),Q=Symbol.for("react.forward_ref"),K=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),re=Symbol.for("react.memo"),O=Symbol.for("react.lazy"),te=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),P=p.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,L=Object.prototype.hasOwnProperty,oe=Array.isArray,C=console.createTask?console.createTask:function(){return null};p={react_stack_bottom_frame:function(e){return e()}};var D,M={},W=p.react_stack_bottom_frame.bind(p,c)(),U=C(l(c)),V={};T.Fragment=j,T.jsx=function(e,r,n){var o=1e4>P.recentlyCreatedOwnerStacks++;return v(e,r,n,!1,o?Error("react-stack-top-frame"):W,o?C(l(e)):U)},T.jsxs=function(e,r,n){var o=1e4>P.recentlyCreatedOwnerStacks++;return v(e,r,n,!0,o?Error("react-stack-top-frame"):W,o?C(l(e)):U)}}()),T}process.env.NODE_ENV==="production"?w.exports=z():w.exports=X();var h=w.exports;function q(t){const s=t.tagName.toLowerCase();return!!(["img","svg","video","canvas","iframe","input","textarea","button"].includes(s)||!(Array.from(t.children).length>0))}function F(t,s){const d=[],l=t.getBoundingClientRect();if(l.width===0||l.height===0)return d;if(q(t)){const c=window.getComputedStyle(t).borderRadius||"0px",m={x:l.left-s.left,y:l.top-s.top,width:l.width,height:l.height,tag:t.tagName.toLowerCase(),borderRadius:c};d.push(m)}else Array.from(t.children).forEach(i=>{d.push(...F(i,s))});return d}const G=({children:t,loading:s=!0,shimmerColor:d="rgba(255, 255, 255, 0.15)",backgroundColor:l="rgba(255, 255, 255, 0.08)",duration:i=1.5,fallbackBorderRadius:c=4,templateProps:m})=>{const[b,S]=f.useState([]),k=f.useRef(null),v=f.useRef(null),g=f.useMemo(()=>{if(!s||!m)return t;const u=f.Children.toArray(t);if(u.length===0)return t;const p=u[0];return f.isValidElement(p)?[f.cloneElement(p,{...m}),...u.slice(1)]:t},[t,s,m]);return f.useLayoutEffect(()=>{if(!s||!v.current)return;const u=v.current,p=u.getBoundingClientRect(),_=[];Array.from(u.children).forEach(A=>{_.push(...F(A,p))}),S(_)},[s,g]),s?h.jsxs("div",{style:{position:"relative"},children:[h.jsx("style",{children:`
22
+ <%s key={someKey} {...props} />`,n,a,R,a),H[a+n]=!0)}if(a=null,o!==void 0&&(l(o),a=""+o),m(r)&&(l(r.key),a=""+r.key),"key"in r){o={};for(var D in r)D!=="key"&&(o[D]=r[D])}else o=r;return a&&b(o,typeof e=="function"?e.displayName||e.name||"Unknown":e),N(e,a,o,u(),A,L)}function S(e){w(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===Y&&(e._payload.status==="fulfilled"?w(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function w(e){return typeof e=="object"&&e!==null&&e.$$typeof===j}var v=i,j=Symbol.for("react.transitional.element"),T=Symbol.for("react.portal"),_=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),C=Symbol.for("react.consumer"),$=Symbol.for("react.context"),te=Symbol.for("react.forward_ref"),oe=Symbol.for("react.suspense"),ne=Symbol.for("react.suspense_list"),ae=Symbol.for("react.memo"),Y=Symbol.for("react.lazy"),se=Symbol.for("react.activity"),ie=Symbol.for("react.client.reference"),I=v.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,z=Object.prototype.hasOwnProperty,ue=Array.isArray,F=console.createTask?console.createTask:function(){return null};v={react_stack_bottom_frame:function(e){return e()}};var X,q={},G=v.react_stack_bottom_frame.bind(v,d)(),J=F(c(d)),H={};k.Fragment=_,k.jsx=function(e,r,o){var n=1e4>I.recentlyCreatedOwnerStacks++;return x(e,r,o,!1,n?Error("react-stack-top-frame"):G,n?F(c(e)):J)},k.jsxs=function(e,r,o){var n=1e4>I.recentlyCreatedOwnerStacks++;return x(e,r,o,!0,n?Error("react-stack-top-frame"):G,n?F(c(e)):J)}}()),k}process.env.NODE_ENV==="production"?O.exports=Z():O.exports=Q();var h=O.exports;const y={shimmerColor:"rgba(255, 255, 255, 0.15)",backgroundColor:"rgba(255, 255, 255, 0.08)",duration:1.5,fallbackBorderRadius:4},W=i.createContext(y),K=({config:t={},children:s})=>{const l=i.useMemo(()=>({shimmerColor:t.shimmerColor??y.shimmerColor,backgroundColor:t.backgroundColor??y.backgroundColor,duration:t.duration??y.duration,fallbackBorderRadius:t.fallbackBorderRadius??y.fallbackBorderRadius}),[t.shimmerColor,t.backgroundColor,t.duration,t.fallbackBorderRadius]);return h.jsx(W.Provider,{value:l,children:s})},U=()=>i.useContext(W);function ee(t){const s=t.tagName.toLowerCase();return!!(["img","svg","video","canvas","iframe","input","textarea","button"].includes(s)||!(Array.from(t.children).length>0))}function V(t,s){const l=[],c=t.getBoundingClientRect();if(c.width===0||c.height===0)return l;if(ee(t)){const d=window.getComputedStyle(t).borderRadius||"0px",m={x:c.left-s.left,y:c.top-s.top,width:c.width,height:c.height,tag:t.tagName.toLowerCase(),borderRadius:d};l.push(m)}else Array.from(t.children).forEach(u=>{l.push(...V(u,s))});return l}const re=({children:t,loading:s=!0,shimmerColor:l,backgroundColor:c,duration:u,fallbackBorderRadius:d,templateProps:m})=>{const b=U(),P=l??b.shimmerColor,N=c??b.backgroundColor,x=u??b.duration,S=d??b.fallbackBorderRadius,[w,v]=i.useState([]),j=i.useRef(null),T=i.useRef(null),_=i.useMemo(()=>{if(!s||!m)return t;const f=i.Children.toArray(t);if(f.length===0)return t;const E=f[0];return i.isValidElement(E)?[i.cloneElement(E,{...m}),...f.slice(1)]:t},[t,s,m]);return i.useLayoutEffect(()=>{if(!s||!T.current)return;const f=T.current,E=f.getBoundingClientRect(),C=[];Array.from(f.children).forEach($=>{C.push(...V($,E))}),v(C)},[s,_]),s?h.jsxs("div",{style:{position:"relative"},children:[h.jsx("style",{children:`
23
23
  .shimmer-measure-container * {
24
24
  color: transparent !important;
25
25
  border-color: transparent !important;
@@ -29,7 +29,7 @@ React keys must be passed directly to JSX without using spread:
29
29
  .shimmer-measure-container video {
30
30
  opacity: 0;
31
31
  }
32
- `}),h.jsx("div",{ref:v,className:"shimmer-measure-container",style:{pointerEvents:"none"},"aria-hidden":"true",children:g}),h.jsxs("div",{ref:k,style:{position:"absolute",top:0,left:0,right:0,bottom:0,overflow:"hidden"},children:[h.jsx("style",{children:`
32
+ `}),h.jsx("div",{ref:T,className:"shimmer-measure-container",style:{pointerEvents:"none"},"aria-hidden":"true",children:_}),h.jsxs("div",{ref:j,style:{position:"absolute",top:0,left:0,right:0,bottom:0,overflow:"hidden"},children:[h.jsx("style",{children:`
33
33
  @keyframes shimmer {
34
34
  0% {
35
35
  transform: translateX(-100%);
@@ -38,4 +38,4 @@ React keys must be passed directly to JSX without using spread:
38
38
  transform: translateX(100%);
39
39
  }
40
40
  }
41
- `}),b.map((u,p)=>h.jsx("div",{style:{position:"absolute",left:`${u.x}px`,top:`${u.y}px`,width:`${u.width}px`,height:`${u.height}px`,backgroundColor:l,borderRadius:u.borderRadius==="0px"?`${c}px`:u.borderRadius,overflow:"hidden"},children:h.jsx("div",{style:{position:"absolute",top:0,left:0,width:"100%",height:"100%",background:`linear-gradient(90deg, transparent, ${d}, transparent)`,animation:`shimmer ${i}s infinite`}})},p))]})]}):h.jsx(h.Fragment,{children:t})};E.Shimmer=G,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})});
41
+ `}),w.map((f,E)=>h.jsx("div",{style:{position:"absolute",left:`${f.x}px`,top:`${f.y}px`,width:`${f.width}px`,height:`${f.height}px`,backgroundColor:N,borderRadius:f.borderRadius==="0px"?`${S}px`:f.borderRadius,overflow:"hidden"},children:h.jsx("div",{style:{position:"absolute",top:0,left:0,width:"100%",height:"100%",background:`linear-gradient(90deg, transparent, ${P}, transparent)`,animation:`shimmer ${x}s infinite`}})},E))]})]}):h.jsx(h.Fragment,{children:t})};p.Shimmer=re,p.ShimmerProvider=K,p.useShimmerConfig=U,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
package/dist/types.d.ts CHANGED
@@ -25,3 +25,4 @@ export interface ShimmerProps {
25
25
  */
26
26
  templateProps?: Record<string, unknown>;
27
27
  }
28
+ export type { ShimmerConfig } from './ShimmerContext';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shimmer-from-structure",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "A React shimmer/skeleton library that automatically adapts to your component's runtime structure",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -12,7 +12,19 @@
12
12
  "dev": "vite",
13
13
  "build": "tsc && vite build",
14
14
  "preview": "vite preview",
15
- "test": "vitest"
15
+ "test": "vitest",
16
+ "lint": "eslint .",
17
+ "format": "prettier --write .",
18
+ "prepare": "husky"
19
+ },
20
+ "lint-staged": {
21
+ "*.{ts,tsx}": [
22
+ "eslint --fix",
23
+ "prettier --write"
24
+ ],
25
+ "*.{json,css,md}": [
26
+ "prettier --write"
27
+ ]
16
28
  },
17
29
  "keywords": [
18
30
  "react",
@@ -38,15 +50,28 @@
38
50
  "@types/node": "^25.0.9",
39
51
  "@types/react": "^19.2.9",
40
52
  "@types/react-dom": "^19.2.3",
53
+ "@typescript-eslint/eslint-plugin": "^8.53.1",
54
+ "@typescript-eslint/parser": "^8.53.1",
41
55
  "@vitejs/plugin-react": "^4.2.1",
42
56
  "@vitest/ui": "^4.0.17",
57
+ "eslint": "^9.39.2",
58
+ "eslint-config-prettier": "^10.1.8",
59
+ "eslint-plugin-prettier": "^5.5.5",
60
+ "eslint-plugin-react": "^7.37.5",
61
+ "eslint-plugin-react-hooks": "^7.0.1",
62
+ "eslint-plugin-react-refresh": "^0.4.26",
63
+ "globals": "^17.1.0",
64
+ "husky": "^9.1.7",
43
65
  "jsdom": "^27.4.0",
66
+ "lint-staged": "^16.2.7",
67
+ "prettier": "^3.8.1",
44
68
  "react": "^19.2.3",
45
69
  "react-dom": "^19.2.3",
46
70
  "recharts": "^3.6.0",
47
71
  "typescript": "^5.3.0",
72
+ "typescript-eslint": "^8.53.1",
48
73
  "vite": "^5.0.0",
49
74
  "vite-plugin-dts": "^4.5.4",
50
75
  "vitest": "^4.0.17"
51
76
  }
52
- }
77
+ }