react-render-guard 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # 🛡️ RenderGuard
1
+ # 🛡️ React Render Guard
2
2
 
3
3
  > **Stop guessing. Start optimizing.**
4
4
  > A lightweight, non-intrusive React library to detect, visualize, and eliminate unnecessary re-renders in your application.
@@ -26,7 +26,8 @@ Finding these bottlenecks manually with general profiling tools is tedious and d
26
26
  - **🔍 Precision Monitoring**: Uses React's internal Profiler API 100% safely.
27
27
  - **⚡ Zero Production Overhead**: Designed to be stripped out or disabled in production.
28
28
  - **🛠️ Developer Experience**: Simple `Provider` API.
29
- - **📊 Real-time Insights**: Console alerts for expensive renders (Visual Overlay coming soon!).
29
+ - **📊 Real-time Insights**: Console alerts for expensive renders.
30
+ - **👁️ Visual Overlay**: A non-intrusive floating panel showing render duration, total render counts, and color-coded health status (Green/Orange/Red) in real-time.
30
31
 
31
32
  ## 📦 Installation
32
33
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { default as React } from 'react';
2
+ interface OverlayProps {
3
+ lastRenderTime: number;
4
+ renderCount: number;
5
+ lastRenderId: string;
6
+ }
7
+ export declare const RenderOverlay: React.FC<OverlayProps>;
8
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,69 +1,70 @@
1
- import K, { useCallback as ee, Profiler as re, useRef as te, useEffect as ne } from "react";
2
- var b = { exports: {} }, E = {};
3
- var I;
4
- function oe() {
5
- if (I) return E;
6
- I = 1;
7
- var l = /* @__PURE__ */ Symbol.for("react.transitional.element"), s = /* @__PURE__ */ Symbol.for("react.fragment");
8
- function i(f, a, u) {
9
- var c = null;
10
- if (u !== void 0 && (c = "" + u), a.key !== void 0 && (c = "" + a.key), "key" in a) {
11
- u = {};
12
- for (var d in a)
13
- d !== "key" && (u[d] = a[d]);
14
- } else u = a;
15
- return a = u.ref, {
16
- $$typeof: l,
17
- type: f,
18
- key: c,
19
- ref: a !== void 0 ? a : null,
20
- props: u
1
+ import C, { useState as D, useEffect as z, Profiler as oe, useCallback as ae, useRef as se } from "react";
2
+ import { createPortal as le } from "react-dom";
3
+ var g = { exports: {} }, x = {};
4
+ var M;
5
+ function ie() {
6
+ if (M) return x;
7
+ M = 1;
8
+ var n = /* @__PURE__ */ Symbol.for("react.transitional.element"), s = /* @__PURE__ */ Symbol.for("react.fragment");
9
+ function p(d, i, c) {
10
+ var u = null;
11
+ if (c !== void 0 && (u = "" + c), i.key !== void 0 && (u = "" + i.key), "key" in i) {
12
+ c = {};
13
+ for (var m in i)
14
+ m !== "key" && (c[m] = i[m]);
15
+ } else c = i;
16
+ return i = c.ref, {
17
+ $$typeof: n,
18
+ type: d,
19
+ key: u,
20
+ ref: i !== void 0 ? i : null,
21
+ props: c
21
22
  };
22
23
  }
23
- return E.Fragment = s, E.jsx = i, E.jsxs = i, E;
24
+ return x.Fragment = s, x.jsx = p, x.jsxs = p, x;
24
25
  }
25
- var _ = {};
26
- var D;
27
- function ae() {
28
- return D || (D = 1, process.env.NODE_ENV !== "production" && (function() {
29
- function l(e) {
26
+ var E = {};
27
+ var G;
28
+ function ce() {
29
+ return G || (G = 1, process.env.NODE_ENV !== "production" && (function() {
30
+ function n(e) {
30
31
  if (e == null) return null;
31
32
  if (typeof e == "function")
32
- return e.$$typeof === B ? null : e.displayName || e.name || null;
33
+ return e.$$typeof === re ? null : e.displayName || e.name || null;
33
34
  if (typeof e == "string") return e;
34
35
  switch (e) {
35
36
  case k:
36
37
  return "Fragment";
37
- case U:
38
+ case q:
38
39
  return "Profiler";
39
- case M:
40
+ case J:
40
41
  return "StrictMode";
41
- case V:
42
+ case Z:
42
43
  return "Suspense";
43
- case z:
44
+ case Q:
44
45
  return "SuspenseList";
45
- case H:
46
+ case ee:
46
47
  return "Activity";
47
48
  }
48
49
  if (typeof e == "object")
49
50
  switch (typeof e.tag == "number" && console.error(
50
51
  "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
51
52
  ), e.$$typeof) {
52
- case W:
53
+ case V:
53
54
  return "Portal";
54
- case q:
55
+ case X:
55
56
  return e.displayName || "Context";
56
- case G:
57
+ case B:
57
58
  return (e._context.displayName || "Context") + ".Consumer";
58
- case J:
59
+ case H:
59
60
  var r = e.render;
60
61
  return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
61
- case X:
62
- return r = e.displayName || null, r !== null ? r : l(e.type) || "Memo";
63
- case O:
62
+ case K:
63
+ return r = e.displayName || null, r !== null ? r : n(e.type) || "Memo";
64
+ case S:
64
65
  r = e._payload, e = e._init;
65
66
  try {
66
- return l(e(r));
67
+ return n(e(r));
67
68
  } catch {
68
69
  }
69
70
  }
@@ -72,7 +73,7 @@ function ae() {
72
73
  function s(e) {
73
74
  return "" + e;
74
75
  }
75
- function i(e) {
76
+ function p(e) {
76
77
  try {
77
78
  s(e);
78
79
  var r = !1;
@@ -81,42 +82,42 @@ function ae() {
81
82
  }
82
83
  if (r) {
83
84
  r = console;
84
- var t = r.error, n = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
85
+ var t = r.error, o = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
85
86
  return t.call(
86
87
  r,
87
88
  "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
88
- n
89
+ o
89
90
  ), s(e);
90
91
  }
91
92
  }
92
- function f(e) {
93
+ function d(e) {
93
94
  if (e === k) return "<>";
94
- if (typeof e == "object" && e !== null && e.$$typeof === O)
95
+ if (typeof e == "object" && e !== null && e.$$typeof === S)
95
96
  return "<...>";
96
97
  try {
97
- var r = l(e);
98
+ var r = n(e);
98
99
  return r ? "<" + r + ">" : "<...>";
99
100
  } catch {
100
101
  return "<...>";
101
102
  }
102
103
  }
103
- function a() {
104
- var e = A.A;
104
+ function i() {
105
+ var e = w.A;
105
106
  return e === null ? null : e.getOwner();
106
107
  }
107
- function u() {
108
+ function c() {
108
109
  return Error("react-stack-top-frame");
109
110
  }
110
- function c(e) {
111
- if (h.call(e, "key")) {
111
+ function u(e) {
112
+ if (I.call(e, "key")) {
112
113
  var r = Object.getOwnPropertyDescriptor(e, "key").get;
113
114
  if (r && r.isReactWarning) return !1;
114
115
  }
115
116
  return e.key !== void 0;
116
117
  }
117
- function d(e, r) {
118
+ function m(e, r) {
118
119
  function t() {
119
- N || (N = !0, console.error(
120
+ F || (F = !0, console.error(
120
121
  "%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)",
121
122
  r
122
123
  ));
@@ -126,23 +127,23 @@ function ae() {
126
127
  configurable: !0
127
128
  });
128
129
  }
129
- function T() {
130
- var e = l(this.type);
131
- return C[e] || (C[e] = !0, console.error(
130
+ function R() {
131
+ var e = n(this.type);
132
+ return Y[e] || (Y[e] = !0, console.error(
132
133
  "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."
133
134
  )), e = this.props.ref, e !== void 0 ? e : null;
134
135
  }
135
- function p(e, r, t, n, v, P) {
136
- var o = t.ref;
136
+ function j(e, r, t, o, y, A) {
137
+ var a = t.ref;
137
138
  return e = {
138
- $$typeof: g,
139
+ $$typeof: N,
139
140
  type: e,
140
141
  key: r,
141
142
  props: t,
142
- _owner: n
143
- }, (o !== void 0 ? o : null) !== null ? Object.defineProperty(e, "ref", {
143
+ _owner: o
144
+ }, (a !== void 0 ? a : null) !== null ? Object.defineProperty(e, "ref", {
144
145
  enumerable: !1,
145
- get: T
146
+ get: R
146
147
  }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
147
148
  configurable: !1,
148
149
  enumerable: !1,
@@ -157,138 +158,270 @@ function ae() {
157
158
  configurable: !1,
158
159
  enumerable: !1,
159
160
  writable: !0,
160
- value: v
161
+ value: y
161
162
  }), Object.defineProperty(e, "_debugTask", {
162
163
  configurable: !1,
163
164
  enumerable: !1,
164
165
  writable: !0,
165
- value: P
166
+ value: A
166
167
  }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
167
168
  }
168
- function x(e, r, t, n, v, P) {
169
- var o = r.children;
170
- if (o !== void 0)
171
- if (n)
172
- if (Z(o)) {
173
- for (n = 0; n < o.length; n++)
174
- y(o[n]);
175
- Object.freeze && Object.freeze(o);
169
+ function _(e, r, t, o, y, A) {
170
+ var a = r.children;
171
+ if (a !== void 0)
172
+ if (o)
173
+ if (te(a)) {
174
+ for (o = 0; o < a.length; o++)
175
+ v(a[o]);
176
+ Object.freeze && Object.freeze(a);
176
177
  } else
177
178
  console.error(
178
179
  "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
179
180
  );
180
- else y(o);
181
- if (h.call(r, "key")) {
182
- o = l(e);
183
- var m = Object.keys(r).filter(function(Q) {
184
- return Q !== "key";
181
+ else v(a);
182
+ if (I.call(r, "key")) {
183
+ a = n(e);
184
+ var b = Object.keys(r).filter(function(ne) {
185
+ return ne !== "key";
185
186
  });
186
- n = 0 < m.length ? "{key: someKey, " + m.join(": ..., ") + ": ...}" : "{key: someKey}", F[o + n] || (m = 0 < m.length ? "{" + m.join(": ..., ") + ": ...}" : "{}", console.error(
187
+ o = 0 < b.length ? "{key: someKey, " + b.join(": ..., ") + ": ...}" : "{key: someKey}", L[a + o] || (b = 0 < b.length ? "{" + b.join(": ..., ") + ": ...}" : "{}", console.error(
187
188
  `A props object containing a "key" prop is being spread into JSX:
188
189
  let props = %s;
189
190
  <%s {...props} />
190
191
  React keys must be passed directly to JSX without using spread:
191
192
  let props = %s;
192
193
  <%s key={someKey} {...props} />`,
193
- n,
194
194
  o,
195
- m,
196
- o
197
- ), F[o + n] = !0);
195
+ a,
196
+ b,
197
+ a
198
+ ), L[a + o] = !0);
198
199
  }
199
- if (o = null, t !== void 0 && (i(t), o = "" + t), c(r) && (i(r.key), o = "" + r.key), "key" in r) {
200
+ if (a = null, t !== void 0 && (p(t), a = "" + t), u(r) && (p(r.key), a = "" + r.key), "key" in r) {
200
201
  t = {};
201
- for (var w in r)
202
- w !== "key" && (t[w] = r[w]);
202
+ for (var P in r)
203
+ P !== "key" && (t[P] = r[P]);
203
204
  } else t = r;
204
- return o && d(
205
+ return a && m(
205
206
  t,
206
207
  typeof e == "function" ? e.displayName || e.name || "Unknown" : e
207
- ), p(
208
+ ), j(
208
209
  e,
209
- o,
210
+ a,
210
211
  t,
211
- a(),
212
- v,
213
- P
212
+ i(),
213
+ y,
214
+ A
214
215
  );
215
216
  }
216
- function y(e) {
217
- j(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === O && (e._payload.status === "fulfilled" ? j(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
217
+ function v(e) {
218
+ T(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === S && (e._payload.status === "fulfilled" ? T(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
218
219
  }
219
- function j(e) {
220
- return typeof e == "object" && e !== null && e.$$typeof === g;
220
+ function T(e) {
221
+ return typeof e == "object" && e !== null && e.$$typeof === N;
221
222
  }
222
- var R = K, g = /* @__PURE__ */ Symbol.for("react.transitional.element"), W = /* @__PURE__ */ Symbol.for("react.portal"), k = /* @__PURE__ */ Symbol.for("react.fragment"), M = /* @__PURE__ */ Symbol.for("react.strict_mode"), U = /* @__PURE__ */ Symbol.for("react.profiler"), G = /* @__PURE__ */ Symbol.for("react.consumer"), q = /* @__PURE__ */ Symbol.for("react.context"), J = /* @__PURE__ */ Symbol.for("react.forward_ref"), V = /* @__PURE__ */ Symbol.for("react.suspense"), z = /* @__PURE__ */ Symbol.for("react.suspense_list"), X = /* @__PURE__ */ Symbol.for("react.memo"), O = /* @__PURE__ */ Symbol.for("react.lazy"), H = /* @__PURE__ */ Symbol.for("react.activity"), B = /* @__PURE__ */ Symbol.for("react.client.reference"), A = R.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, h = Object.prototype.hasOwnProperty, Z = Array.isArray, S = console.createTask ? console.createTask : function() {
223
+ var h = C, N = /* @__PURE__ */ Symbol.for("react.transitional.element"), V = /* @__PURE__ */ Symbol.for("react.portal"), k = /* @__PURE__ */ Symbol.for("react.fragment"), J = /* @__PURE__ */ Symbol.for("react.strict_mode"), q = /* @__PURE__ */ Symbol.for("react.profiler"), B = /* @__PURE__ */ Symbol.for("react.consumer"), X = /* @__PURE__ */ Symbol.for("react.context"), H = /* @__PURE__ */ Symbol.for("react.forward_ref"), Z = /* @__PURE__ */ Symbol.for("react.suspense"), Q = /* @__PURE__ */ Symbol.for("react.suspense_list"), K = /* @__PURE__ */ Symbol.for("react.memo"), S = /* @__PURE__ */ Symbol.for("react.lazy"), ee = /* @__PURE__ */ Symbol.for("react.activity"), re = /* @__PURE__ */ Symbol.for("react.client.reference"), w = h.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, I = Object.prototype.hasOwnProperty, te = Array.isArray, O = console.createTask ? console.createTask : function() {
223
224
  return null;
224
225
  };
225
- R = {
226
+ h = {
226
227
  react_stack_bottom_frame: function(e) {
227
228
  return e();
228
229
  }
229
230
  };
230
- var N, C = {}, $ = R.react_stack_bottom_frame.bind(
231
- R,
232
- u
233
- )(), Y = S(f(u)), F = {};
234
- _.Fragment = k, _.jsx = function(e, r, t) {
235
- var n = 1e4 > A.recentlyCreatedOwnerStacks++;
236
- return x(
231
+ var F, Y = {}, $ = h.react_stack_bottom_frame.bind(
232
+ h,
233
+ c
234
+ )(), W = O(d(c)), L = {};
235
+ E.Fragment = k, E.jsx = function(e, r, t) {
236
+ var o = 1e4 > w.recentlyCreatedOwnerStacks++;
237
+ return _(
237
238
  e,
238
239
  r,
239
240
  t,
240
241
  !1,
241
- n ? Error("react-stack-top-frame") : $,
242
- n ? S(f(e)) : Y
242
+ o ? Error("react-stack-top-frame") : $,
243
+ o ? O(d(e)) : W
243
244
  );
244
- }, _.jsxs = function(e, r, t) {
245
- var n = 1e4 > A.recentlyCreatedOwnerStacks++;
246
- return x(
245
+ }, E.jsxs = function(e, r, t) {
246
+ var o = 1e4 > w.recentlyCreatedOwnerStacks++;
247
+ return _(
247
248
  e,
248
249
  r,
249
250
  t,
250
251
  !0,
251
- n ? Error("react-stack-top-frame") : $,
252
- n ? S(f(e)) : Y
252
+ o ? Error("react-stack-top-frame") : $,
253
+ o ? O(d(e)) : W
253
254
  );
254
255
  };
255
- })()), _;
256
+ })()), E;
256
257
  }
257
- var L;
258
- function se() {
259
- return L || (L = 1, process.env.NODE_ENV === "production" ? b.exports = oe() : b.exports = ae()), b.exports;
258
+ var U;
259
+ function ue() {
260
+ return U || (U = 1, process.env.NODE_ENV === "production" ? g.exports = ie() : g.exports = ce()), g.exports;
260
261
  }
261
- var ue = se();
262
- const le = 3, ie = ({
263
- children: l,
262
+ var l = ue();
263
+ const f = {
264
+ container: {
265
+ position: "fixed",
266
+ bottom: "20px",
267
+ right: "20px",
268
+ backgroundColor: "rgba(0, 0, 0, 0.85)",
269
+ color: "#fff",
270
+ padding: "12px",
271
+ borderRadius: "8px",
272
+ fontFamily: "monospace",
273
+ fontSize: "12px",
274
+ zIndex: 9999,
275
+ boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
276
+ minWidth: "200px",
277
+ border: "1px solid #333",
278
+ backdropFilter: "blur(4px)",
279
+ transition: "border-color 0.3s ease"
280
+ },
281
+ metricRow: {
282
+ display: "flex",
283
+ justifyContent: "space-between",
284
+ marginBottom: "4px"
285
+ },
286
+ label: {
287
+ color: "#aaa"
288
+ },
289
+ value: {
290
+ fontWeight: "bold"
291
+ },
292
+ indicator: {
293
+ display: "inline-block",
294
+ width: "8px",
295
+ height: "8px",
296
+ borderRadius: "50%",
297
+ marginRight: "8px"
298
+ },
299
+ title: {
300
+ margin: "0 0 8px 0",
301
+ fontSize: "14px",
302
+ fontWeight: "bold",
303
+ borderBottom: "1px solid #444",
304
+ paddingBottom: "4px",
305
+ display: "flex",
306
+ alignItems: "center"
307
+ }
308
+ }, fe = (n) => n < 16 ? "#4caf50" : n < 50 ? "#ff9800" : "#f44336", de = ({
309
+ lastRenderTime: n,
310
+ renderCount: s,
311
+ lastRenderId: p
312
+ }) => {
313
+ const [d, i] = D(!1), [c, u] = D(!1);
314
+ if (z(() => {
315
+ if (s > 0) {
316
+ i(!0), u(!0);
317
+ const R = setTimeout(() => u(!1), 300);
318
+ return () => clearTimeout(R);
319
+ }
320
+ }, [s, n]), !d) return null;
321
+ const m = fe(n);
322
+ return /* @__PURE__ */ l.jsxs(
323
+ "div",
324
+ {
325
+ style: {
326
+ ...f.container,
327
+ borderColor: c ? m : "#333"
328
+ },
329
+ children: [
330
+ /* @__PURE__ */ l.jsxs("h4", { style: f.title, children: [
331
+ /* @__PURE__ */ l.jsx(
332
+ "span",
333
+ {
334
+ style: { ...f.indicator, backgroundColor: m }
335
+ }
336
+ ),
337
+ "RenderGuard"
338
+ ] }),
339
+ /* @__PURE__ */ l.jsxs("div", { style: f.metricRow, children: [
340
+ /* @__PURE__ */ l.jsx("span", { style: f.label, children: "Last Render:" }),
341
+ /* @__PURE__ */ l.jsxs("span", { style: { ...f.value, color: m }, children: [
342
+ n.toFixed(2),
343
+ "ms"
344
+ ] })
345
+ ] }),
346
+ /* @__PURE__ */ l.jsxs("div", { style: f.metricRow, children: [
347
+ /* @__PURE__ */ l.jsx("span", { style: f.label, children: "Total Renders:" }),
348
+ /* @__PURE__ */ l.jsx("span", { style: f.value, children: s })
349
+ ] }),
350
+ /* @__PURE__ */ l.jsxs("div", { style: f.metricRow, children: [
351
+ /* @__PURE__ */ l.jsx("span", { style: f.label, children: "Source:" }),
352
+ /* @__PURE__ */ l.jsx(
353
+ "span",
354
+ {
355
+ style: {
356
+ ...f.value,
357
+ maxWidth: "100px",
358
+ whiteSpace: "nowrap",
359
+ overflow: "hidden",
360
+ textOverflow: "ellipsis"
361
+ },
362
+ children: p
363
+ }
364
+ )
365
+ ] })
366
+ ]
367
+ }
368
+ );
369
+ }, me = 3, pe = C.memo(
370
+ ({
371
+ children: n,
372
+ onRender: s
373
+ }) => /* @__PURE__ */ l.jsx(oe, { id: "RenderGuardRoot", onRender: s, children: n })
374
+ ), xe = ({
375
+ children: n,
264
376
  onRenderCallback: s,
265
- threshold: i = le
377
+ threshold: p = me
266
378
  }) => {
267
- const f = ee(
268
- (a, u, c, d, T, p) => {
269
- c > 5 && console.warn(
270
- `[RenderGuard] Slow render detected in ${a}: ${c.toFixed(2)}ms`
379
+ const [d, i] = C.useState({
380
+ lastRenderTime: 0,
381
+ renderCount: 0,
382
+ lastRenderId: ""
383
+ }), c = ae(
384
+ (u, m, R, j, _, v) => {
385
+ i((T) => ({
386
+ lastRenderTime: R,
387
+ renderCount: T.renderCount + 1,
388
+ lastRenderId: u
389
+ })), R > 5 && console.warn(
390
+ `[RenderGuard] Slow render detected in ${u}: ${R.toFixed(2)}ms`
271
391
  ), s && s(
272
- a,
273
392
  u,
274
- c,
275
- d,
276
- T,
277
- p
393
+ m,
394
+ R,
395
+ j,
396
+ _,
397
+ v
278
398
  );
279
399
  },
280
- [s, i]
400
+ [s, p]
281
401
  );
282
- return /* @__PURE__ */ ue.jsx(re, { id: "RenderGuardRoot", onRender: f, children: l });
283
- }, fe = (l) => {
284
- const s = te(0);
285
- return ne(() => {
402
+ return /* @__PURE__ */ l.jsxs(l.Fragment, { children: [
403
+ /* @__PURE__ */ l.jsx(pe, { onRender: c, children: n }),
404
+ typeof document < "u" && le(
405
+ /* @__PURE__ */ l.jsx(
406
+ de,
407
+ {
408
+ lastRenderTime: d.lastRenderTime,
409
+ renderCount: d.renderCount,
410
+ lastRenderId: d.lastRenderId
411
+ }
412
+ ),
413
+ document.body
414
+ )
415
+ ] });
416
+ }, Ee = (n) => {
417
+ const s = se(0);
418
+ return z(() => {
286
419
  s.current += 1, console.log(
287
- `[RenderGuard] ${l} rendered ${s.current} times`
420
+ `[RenderGuard] ${n} rendered ${s.current} times`
288
421
  );
289
422
  }), s.current;
290
423
  };
291
424
  export {
292
- ie as RenderGuard,
293
- fe as useRenderCheck
425
+ xe as RenderGuard,
426
+ Ee as useRenderCheck
294
427
  };
@@ -1,6 +1,6 @@
1
- (function(f,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],c):(f=typeof globalThis<"u"?globalThis:f||self,c(f.RenderGuard={},f.React))})(this,(function(f,c){"use strict";var p={exports:{}},_={};var j;function U(){if(j)return _;j=1;var l=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function d(m,a,u){var i=null;if(u!==void 0&&(i=""+u),a.key!==void 0&&(i=""+a.key),"key"in a){u={};for(var E in a)E!=="key"&&(u[E]=a[E])}else u=a;return a=u.ref,{$$typeof:l,type:m,key:i,ref:a!==void 0?a:null,props:u}}return _.Fragment=s,_.jsx=d,_.jsxs=d,_}var b={};var x;function $(){return x||(x=1,process.env.NODE_ENV!=="production"&&(function(){function l(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ae?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case S:return"Fragment";case Z:return"Profiler";case B:return"StrictMode";case re:return"Suspense";case te:return"SuspenseList";case oe: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 H:return"Portal";case K:return e.displayName||"Context";case Q:return(e._context.displayName||"Context")+".Consumer";case ee:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ne:return r=e.displayName||null,r!==null?r:l(e.type)||"Memo";case A:r=e._payload,e=e._init;try{return l(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 t=r.error,n=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return t.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 m(e){if(e===S)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===A)return"<...>";try{var r=l(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function a(){var e=y.A;return e===null?null:e.getOwner()}function u(){return Error("react-stack-top-frame")}function i(e){if(I.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function E(e,r){function t(){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))}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}function k(){var e=l(this.type);return L[e]||(L[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 O(e,r,t,n,T,h){var o=t.ref;return e={$$typeof:F,type:e,key:r,props:t,_owner:n},(o!==void 0?o:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:k}):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:T}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:h}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function N(e,r,t,n,T,h){var o=r.children;if(o!==void 0)if(n)if(se(o)){for(n=0;n<o.length;n++)C(o[n]);Object.freeze&&Object.freeze(o)}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 C(o);if(I.call(r,"key")){o=l(e);var R=Object.keys(r).filter(function(ue){return ue!=="key"});n=0<R.length?"{key: someKey, "+R.join(": ..., ")+": ...}":"{key: someKey}",W[o+n]||(R=0<R.length?"{"+R.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
1
+ (function(b,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react"),require("react-dom")):typeof define=="function"&&define.amd?define(["exports","react","react-dom"],u):(b=typeof globalThis<"u"?globalThis:b||self,u(b.RenderGuard={},b.React,b.ReactDOM))})(this,(function(b,u,z){"use strict";var T={exports:{}},_={};var I;function V(){if(I)return _;I=1;var n=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function R(m,i,c){var f=null;if(c!==void 0&&(f=""+c),i.key!==void 0&&(f=""+i.key),"key"in i){c={};for(var p in i)p!=="key"&&(c[p]=i[p])}else c=i;return i=c.ref,{$$typeof:n,type:m,key:f,ref:i!==void 0?i:null,props:c}}return _.Fragment=s,_.jsx=R,_.jsxs=R,_}var v={};var F;function q(){return F||(F=1,process.env.NODE_ENV!=="production"&&(function(){function n(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ce?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case w:return"Fragment";case te:return"Profiler";case re:return"StrictMode";case se:return"Suspense";case le:return"SuspenseList";case ue: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 ee:return"Portal";case oe:return e.displayName||"Context";case ne:return(e._context.displayName||"Context")+".Consumer";case ae:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ie:return r=e.displayName||null,r!==null?r:n(e.type)||"Memo";case O:r=e._payload,e=e._init;try{return n(e(r))}catch{}}return null}function s(e){return""+e}function R(e){try{s(e);var r=!1}catch{r=!0}if(r){r=console;var t=r.error,o=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return t.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 m(e){if(e===w)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===O)return"<...>";try{var r=n(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function i(){var e=A.A;return e===null?null:e.getOwner()}function c(){return Error("react-stack-top-frame")}function f(e){if(W.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function p(e,r){function t(){L||(L=!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))}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}function E(){var e=n(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,t,o,g,C){var a=t.ref;return e={$$typeof:$,type:e,key:r,props:t,_owner:o},(a!==void 0?a:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:E}):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:g}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:C}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function h(e,r,t,o,g,C){var a=r.children;if(a!==void 0)if(o)if(de(a)){for(o=0;o<a.length;o++)y(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 y(a);if(W.call(r,"key")){a=n(e);var x=Object.keys(r).filter(function(fe){return fe!=="key"});o=0<x.length?"{key: someKey, "+x.join(": ..., ")+": ...}":"{key: someKey}",U[a+o]||(x=0<x.length?"{"+x.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
2
  let props = %s;
3
3
  <%s {...props} />
4
4
  React keys must be passed directly to JSX without using spread:
5
5
  let props = %s;
6
- <%s key={someKey} {...props} />`,n,o,R,o),W[o+n]=!0)}if(o=null,t!==void 0&&(d(t),o=""+t),i(r)&&(d(r.key),o=""+r.key),"key"in r){t={};for(var w in r)w!=="key"&&(t[w]=r[w])}else t=r;return o&&E(t,typeof e=="function"?e.displayName||e.name||"Unknown":e),O(e,o,t,a(),T,h)}function C(e){Y(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===A&&(e._payload.status==="fulfilled"?Y(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function Y(e){return typeof e=="object"&&e!==null&&e.$$typeof===F}var v=c,F=Symbol.for("react.transitional.element"),H=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),B=Symbol.for("react.strict_mode"),Z=Symbol.for("react.profiler"),Q=Symbol.for("react.consumer"),K=Symbol.for("react.context"),ee=Symbol.for("react.forward_ref"),re=Symbol.for("react.suspense"),te=Symbol.for("react.suspense_list"),ne=Symbol.for("react.memo"),A=Symbol.for("react.lazy"),oe=Symbol.for("react.activity"),ae=Symbol.for("react.client.reference"),y=v.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,I=Object.prototype.hasOwnProperty,se=Array.isArray,P=console.createTask?console.createTask:function(){return null};v={react_stack_bottom_frame:function(e){return e()}};var D,L={},G=v.react_stack_bottom_frame.bind(v,u)(),M=P(m(u)),W={};b.Fragment=S,b.jsx=function(e,r,t){var n=1e4>y.recentlyCreatedOwnerStacks++;return N(e,r,t,!1,n?Error("react-stack-top-frame"):G,n?P(m(e)):M)},b.jsxs=function(e,r,t){var n=1e4>y.recentlyCreatedOwnerStacks++;return N(e,r,t,!0,n?Error("react-stack-top-frame"):G,n?P(m(e)):M)}})()),b}var g;function J(){return g||(g=1,process.env.NODE_ENV==="production"?p.exports=U():p.exports=$()),p.exports}var V=J();const z=3,X=({children:l,onRenderCallback:s,threshold:d=z})=>{const m=c.useCallback((a,u,i,E,k,O)=>{i>5&&console.warn(`[RenderGuard] Slow render detected in ${a}: ${i.toFixed(2)}ms`),s&&s(a,u,i,E,k,O)},[s,d]);return V.jsx(c.Profiler,{id:"RenderGuardRoot",onRender:m,children:l})},q=l=>{const s=c.useRef(0);return c.useEffect(()=>{s.current+=1,console.log(`[RenderGuard] ${l} rendered ${s.current} times`)}),s.current};f.RenderGuard=X,f.useRenderCheck=q,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})}));
6
+ <%s key={someKey} {...props} />`,o,a,x,a),U[a+o]=!0)}if(a=null,t!==void 0&&(R(t),a=""+t),f(r)&&(R(r.key),a=""+r.key),"key"in r){t={};for(var N in r)N!=="key"&&(t[N]=r[N])}else t=r;return a&&p(t,typeof e=="function"?e.displayName||e.name||"Unknown":e),k(e,a,t,i(),g,C)}function y(e){j(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===O&&(e._payload.status==="fulfilled"?j(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function j(e){return typeof e=="object"&&e!==null&&e.$$typeof===$}var S=u,$=Symbol.for("react.transitional.element"),ee=Symbol.for("react.portal"),w=Symbol.for("react.fragment"),re=Symbol.for("react.strict_mode"),te=Symbol.for("react.profiler"),ne=Symbol.for("react.consumer"),oe=Symbol.for("react.context"),ae=Symbol.for("react.forward_ref"),se=Symbol.for("react.suspense"),le=Symbol.for("react.suspense_list"),ie=Symbol.for("react.memo"),O=Symbol.for("react.lazy"),ue=Symbol.for("react.activity"),ce=Symbol.for("react.client.reference"),A=S.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,W=Object.prototype.hasOwnProperty,de=Array.isArray,P=console.createTask?console.createTask:function(){return null};S={react_stack_bottom_frame:function(e){return e()}};var L,M={},D=S.react_stack_bottom_frame.bind(S,c)(),G=P(m(c)),U={};v.Fragment=w,v.jsx=function(e,r,t){var o=1e4>A.recentlyCreatedOwnerStacks++;return h(e,r,t,!1,o?Error("react-stack-top-frame"):D,o?P(m(e)):G)},v.jsxs=function(e,r,t){var o=1e4>A.recentlyCreatedOwnerStacks++;return h(e,r,t,!0,o?Error("react-stack-top-frame"):D,o?P(m(e)):G)}})()),v}var Y;function J(){return Y||(Y=1,process.env.NODE_ENV==="production"?T.exports=V():T.exports=q()),T.exports}var l=J();const d={container:{position:"fixed",bottom:"20px",right:"20px",backgroundColor:"rgba(0, 0, 0, 0.85)",color:"#fff",padding:"12px",borderRadius:"8px",fontFamily:"monospace",fontSize:"12px",zIndex:9999,boxShadow:"0 4px 12px rgba(0,0,0,0.3)",minWidth:"200px",border:"1px solid #333",backdropFilter:"blur(4px)",transition:"border-color 0.3s ease"},metricRow:{display:"flex",justifyContent:"space-between",marginBottom:"4px"},label:{color:"#aaa"},value:{fontWeight:"bold"},indicator:{display:"inline-block",width:"8px",height:"8px",borderRadius:"50%",marginRight:"8px"},title:{margin:"0 0 8px 0",fontSize:"14px",fontWeight:"bold",borderBottom:"1px solid #444",paddingBottom:"4px",display:"flex",alignItems:"center"}},B=n=>n<16?"#4caf50":n<50?"#ff9800":"#f44336",X=({lastRenderTime:n,renderCount:s,lastRenderId:R})=>{const[m,i]=u.useState(!1),[c,f]=u.useState(!1);if(u.useEffect(()=>{if(s>0){i(!0),f(!0);const E=setTimeout(()=>f(!1),300);return()=>clearTimeout(E)}},[s,n]),!m)return null;const p=B(n);return l.jsxs("div",{style:{...d.container,borderColor:c?p:"#333"},children:[l.jsxs("h4",{style:d.title,children:[l.jsx("span",{style:{...d.indicator,backgroundColor:p}}),"RenderGuard"]}),l.jsxs("div",{style:d.metricRow,children:[l.jsx("span",{style:d.label,children:"Last Render:"}),l.jsxs("span",{style:{...d.value,color:p},children:[n.toFixed(2),"ms"]})]}),l.jsxs("div",{style:d.metricRow,children:[l.jsx("span",{style:d.label,children:"Total Renders:"}),l.jsx("span",{style:d.value,children:s})]}),l.jsxs("div",{style:d.metricRow,children:[l.jsx("span",{style:d.label,children:"Source:"}),l.jsx("span",{style:{...d.value,maxWidth:"100px",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:R})]})]})},H=3,Z=u.memo(({children:n,onRender:s})=>l.jsx(u.Profiler,{id:"RenderGuardRoot",onRender:s,children:n})),Q=({children:n,onRenderCallback:s,threshold:R=H})=>{const[m,i]=u.useState({lastRenderTime:0,renderCount:0,lastRenderId:""}),c=u.useCallback((f,p,E,k,h,y)=>{i(j=>({lastRenderTime:E,renderCount:j.renderCount+1,lastRenderId:f})),E>5&&console.warn(`[RenderGuard] Slow render detected in ${f}: ${E.toFixed(2)}ms`),s&&s(f,p,E,k,h,y)},[s,R]);return l.jsxs(l.Fragment,{children:[l.jsx(Z,{onRender:c,children:n}),typeof document<"u"&&z.createPortal(l.jsx(X,{lastRenderTime:m.lastRenderTime,renderCount:m.renderCount,lastRenderId:m.lastRenderId}),document.body)]})},K=n=>{const s=u.useRef(0);return u.useEffect(()=>{s.current+=1,console.log(`[RenderGuard] ${n} rendered ${s.current} times`)}),s.current};b.RenderGuard=Q,b.useRenderCheck=K,Object.defineProperty(b,Symbol.toStringTag,{value:"Module"})}));
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-render-guard",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "./dist/render-guard.umd.js",
6
6
  "module": "./dist/render-guard.es.js",
@@ -16,7 +16,8 @@
16
16
  ],
17
17
  "scripts": {
18
18
  "build": "tsc && vite build",
19
- "dev": "vite build --watch"
19
+ "dev": "vite build --watch",
20
+ "test": "vitest"
20
21
  },
21
22
  "keywords": [
22
23
  "react",
@@ -36,14 +37,19 @@
36
37
  "react-dom": ">=16.8.0"
37
38
  },
38
39
  "devDependencies": {
40
+ "@testing-library/dom": "^10.4.1",
41
+ "@testing-library/jest-dom": "^6.9.1",
42
+ "@testing-library/react": "^16.3.2",
39
43
  "@types/node": "^25.2.0",
40
44
  "@types/react": "^19.2.11",
41
45
  "@types/react-dom": "^19.2.3",
42
46
  "@vitejs/plugin-react": "^5.1.3",
47
+ "jsdom": "^28.0.0",
43
48
  "react": "^19.2.4",
44
49
  "react-dom": "^19.2.4",
45
50
  "typescript": "^5.9.3",
46
51
  "vite": "^7.3.1",
47
- "vite-plugin-dts": "^4.5.4"
52
+ "vite-plugin-dts": "^4.5.4",
53
+ "vitest": "^4.0.18"
48
54
  }
49
55
  }