react-dev-profiler 1.0.2 → 1.1.1
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/dist/index.cjs +140 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +148 -117
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
DevProfiler: () => DevProfiler
|
|
23
|
+
DevProfiler: () => DevProfiler,
|
|
24
|
+
default: () => DevProfiler
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(index_exports);
|
|
26
27
|
|
|
@@ -79,15 +80,15 @@ var s = {
|
|
|
79
80
|
backdropFilter: "blur(12px)",
|
|
80
81
|
userSelect: "none",
|
|
81
82
|
color: "#ccc",
|
|
82
|
-
fontSize: 11
|
|
83
|
+
fontSize: 11,
|
|
84
|
+
cursor: "grab",
|
|
85
|
+
touchAction: "none"
|
|
83
86
|
},
|
|
84
87
|
panelHeader: {
|
|
85
88
|
display: "flex",
|
|
86
89
|
justifyContent: "space-between",
|
|
87
90
|
alignItems: "center",
|
|
88
|
-
marginBottom: 8
|
|
89
|
-
cursor: "grab",
|
|
90
|
-
touchAction: "none"
|
|
91
|
+
marginBottom: 8
|
|
91
92
|
},
|
|
92
93
|
panelTitle: {
|
|
93
94
|
color: "#666",
|
|
@@ -118,7 +119,8 @@ var s = {
|
|
|
118
119
|
border: "none",
|
|
119
120
|
color: "#444",
|
|
120
121
|
cursor: "pointer",
|
|
121
|
-
padding:
|
|
122
|
+
padding: 4,
|
|
123
|
+
margin: -4,
|
|
122
124
|
lineHeight: 1,
|
|
123
125
|
display: "flex",
|
|
124
126
|
alignItems: "center",
|
|
@@ -133,7 +135,8 @@ var s = {
|
|
|
133
135
|
color: "#444",
|
|
134
136
|
cursor: "pointer",
|
|
135
137
|
fontSize: 13,
|
|
136
|
-
padding:
|
|
138
|
+
padding: 4,
|
|
139
|
+
margin: -4,
|
|
137
140
|
lineHeight: 1
|
|
138
141
|
},
|
|
139
142
|
body: {
|
|
@@ -182,23 +185,40 @@ var s = {
|
|
|
182
185
|
toggleBtn: {
|
|
183
186
|
position: "fixed",
|
|
184
187
|
zIndex: 99998,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
background: "rgba(20, 20, 20, 0.9)",
|
|
188
|
+
height: 26,
|
|
189
|
+
borderRadius: 13,
|
|
190
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
191
|
+
background: "rgba(28, 28, 30, 0.92)",
|
|
190
192
|
cursor: "pointer",
|
|
191
193
|
display: "flex",
|
|
192
194
|
alignItems: "center",
|
|
193
|
-
|
|
194
|
-
padding: "0
|
|
195
|
-
backdropFilter: "blur(
|
|
195
|
+
gap: 6,
|
|
196
|
+
padding: "0 10px 0 8px",
|
|
197
|
+
backdropFilter: "blur(20px)",
|
|
198
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
199
|
+
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.4), inset 0 0.5px 0 rgba(255, 255, 255, 0.06)"
|
|
200
|
+
},
|
|
201
|
+
toggleDot: {
|
|
202
|
+
width: 6,
|
|
203
|
+
height: 6,
|
|
204
|
+
borderRadius: "50%",
|
|
205
|
+
flexShrink: 0
|
|
196
206
|
},
|
|
197
207
|
toggleFps: {
|
|
198
208
|
fontFamily: "'SF Mono', 'Fira Code', monospace",
|
|
199
|
-
fontSize:
|
|
200
|
-
fontWeight:
|
|
201
|
-
|
|
209
|
+
fontSize: 11,
|
|
210
|
+
fontWeight: 600,
|
|
211
|
+
color: "rgba(255, 255, 255, 0.85)",
|
|
212
|
+
letterSpacing: -0.3,
|
|
213
|
+
lineHeight: 1
|
|
214
|
+
},
|
|
215
|
+
toggleLabel: {
|
|
216
|
+
fontFamily: "'SF Mono', 'Fira Code', monospace",
|
|
217
|
+
fontSize: 9,
|
|
218
|
+
fontWeight: 500,
|
|
219
|
+
color: "rgba(255, 255, 255, 0.35)",
|
|
220
|
+
letterSpacing: 0,
|
|
221
|
+
textTransform: "lowercase"
|
|
202
222
|
},
|
|
203
223
|
footer: {
|
|
204
224
|
marginTop: 8,
|
|
@@ -210,32 +230,59 @@ var s = {
|
|
|
210
230
|
var FLASH_OUTLINE = "2px solid rgba(99, 102, 241, 0.8)";
|
|
211
231
|
|
|
212
232
|
// src/hooks.ts
|
|
233
|
+
function getEffectiveRect(el) {
|
|
234
|
+
const rect = el.getBoundingClientRect();
|
|
235
|
+
if (rect.width > 0 || rect.height > 0) return rect;
|
|
236
|
+
const children = el.children;
|
|
237
|
+
if (children.length === 0) return rect;
|
|
238
|
+
let top = Infinity, left = Infinity, bottom = -Infinity, right = -Infinity;
|
|
239
|
+
for (let i = 0; i < children.length; i++) {
|
|
240
|
+
const cr = children[i].getBoundingClientRect();
|
|
241
|
+
if (cr.width === 0 && cr.height === 0) continue;
|
|
242
|
+
top = Math.min(top, cr.top);
|
|
243
|
+
left = Math.min(left, cr.left);
|
|
244
|
+
bottom = Math.max(bottom, cr.bottom);
|
|
245
|
+
right = Math.max(right, cr.right);
|
|
246
|
+
}
|
|
247
|
+
if (top === Infinity) return rect;
|
|
248
|
+
return new DOMRect(left, top, right - left, bottom - top);
|
|
249
|
+
}
|
|
250
|
+
function getObservableChildren(el) {
|
|
251
|
+
const result = [];
|
|
252
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
253
|
+
const child = el.children[i];
|
|
254
|
+
const r = child.getBoundingClientRect();
|
|
255
|
+
if (r.width > 0 || r.height > 0) result.push(child);
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
213
259
|
function useAnchorPosition(ref, position = "bottom-left") {
|
|
214
260
|
const [pos, setPos] = (0, import_react.useState)({ top: 0, left: 0 });
|
|
215
261
|
(0, import_react.useEffect)(() => {
|
|
216
262
|
if (!ref.current) return;
|
|
263
|
+
const el = ref.current;
|
|
217
264
|
const update = () => {
|
|
218
|
-
|
|
219
|
-
const rect = ref.current.getBoundingClientRect();
|
|
220
|
-
const margin = 8;
|
|
265
|
+
const rect = getEffectiveRect(el);
|
|
221
266
|
switch (position) {
|
|
222
267
|
case "top-left":
|
|
223
|
-
setPos({ top: rect.top
|
|
268
|
+
setPos({ top: rect.top, left: rect.left });
|
|
224
269
|
break;
|
|
225
270
|
case "top-right":
|
|
226
|
-
setPos({ top: rect.top
|
|
271
|
+
setPos({ top: rect.top, left: rect.right });
|
|
227
272
|
break;
|
|
228
273
|
case "bottom-right":
|
|
229
|
-
setPos({ top: rect.bottom
|
|
274
|
+
setPos({ top: rect.bottom, left: rect.right });
|
|
230
275
|
break;
|
|
231
276
|
case "bottom-left":
|
|
232
277
|
default:
|
|
233
|
-
setPos({ top: rect.bottom
|
|
278
|
+
setPos({ top: rect.bottom, left: rect.left });
|
|
234
279
|
break;
|
|
235
280
|
}
|
|
236
281
|
};
|
|
282
|
+
update();
|
|
237
283
|
const observer = new ResizeObserver(update);
|
|
238
|
-
observer.observe(
|
|
284
|
+
observer.observe(el);
|
|
285
|
+
for (const child of getObservableChildren(el)) observer.observe(child);
|
|
239
286
|
observer.observe(document.documentElement);
|
|
240
287
|
return () => observer.disconnect();
|
|
241
288
|
}, [ref, position]);
|
|
@@ -246,9 +293,10 @@ function useDraggable() {
|
|
|
246
293
|
const dragging = (0, import_react.useRef)(false);
|
|
247
294
|
const start = (0, import_react.useRef)({ x: 0, y: 0 });
|
|
248
295
|
const onPointerDown = (0, import_react.useCallback)((e) => {
|
|
296
|
+
if (e.target.closest("button, a, [data-no-drag]")) return;
|
|
249
297
|
dragging.current = true;
|
|
250
298
|
start.current = { x: e.clientX - offset.x, y: e.clientY - offset.y };
|
|
251
|
-
e.
|
|
299
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
252
300
|
}, [offset]);
|
|
253
301
|
const onPointerMove = (0, import_react.useCallback)((e) => {
|
|
254
302
|
if (!dragging.current) return;
|
|
@@ -268,21 +316,13 @@ function useDomTracker(wrapperRef, enabled) {
|
|
|
268
316
|
const dirty = (0, import_react.useRef)(true);
|
|
269
317
|
(0, import_react.useEffect)(() => {
|
|
270
318
|
if (!enabled || !wrapperRef.current) return;
|
|
271
|
-
const observer = new MutationObserver((
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (record.type === "attributes" && record.attributeName === "class") continue;
|
|
275
|
-
realMutation = true;
|
|
276
|
-
}
|
|
277
|
-
if (realMutation) {
|
|
278
|
-
mutations.current++;
|
|
279
|
-
dirty.current = true;
|
|
280
|
-
}
|
|
319
|
+
const observer = new MutationObserver(() => {
|
|
320
|
+
mutations.current++;
|
|
321
|
+
dirty.current = true;
|
|
281
322
|
});
|
|
282
323
|
observer.observe(wrapperRef.current, {
|
|
283
324
|
childList: true,
|
|
284
325
|
subtree: true,
|
|
285
|
-
attributes: true,
|
|
286
326
|
attributeFilter: ["style"]
|
|
287
327
|
});
|
|
288
328
|
return () => observer.disconnect();
|
|
@@ -323,18 +363,19 @@ function useRenderFlash(wrapperRef, open) {
|
|
|
323
363
|
const mutationCount = (0, import_react.useRef)(0);
|
|
324
364
|
(0, import_react.useEffect)(() => {
|
|
325
365
|
if (!open || !wrapperRef.current) return;
|
|
366
|
+
const wrapper = wrapperRef.current;
|
|
326
367
|
const observer = new MutationObserver(() => {
|
|
327
368
|
mutationCount.current++;
|
|
328
|
-
if (
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
369
|
+
if (mutationCount.current <= 1) return;
|
|
370
|
+
const target = getObservableChildren(wrapper)[0] ?? wrapper;
|
|
371
|
+
target.style.outline = FLASH_OUTLINE;
|
|
372
|
+
target.style.outlineOffset = "-2px";
|
|
332
373
|
setTimeout(() => {
|
|
333
|
-
|
|
334
|
-
|
|
374
|
+
target.style.outline = "";
|
|
375
|
+
target.style.outlineOffset = "";
|
|
335
376
|
}, 150);
|
|
336
377
|
});
|
|
337
|
-
observer.observe(
|
|
378
|
+
observer.observe(wrapper, { childList: true, subtree: true });
|
|
338
379
|
return () => observer.disconnect();
|
|
339
380
|
}, [wrapperRef, open]);
|
|
340
381
|
}
|
|
@@ -407,20 +448,21 @@ function StatRow({ label, value, sub, color = "#4ade80" }) {
|
|
|
407
448
|
] })
|
|
408
449
|
] });
|
|
409
450
|
}
|
|
451
|
+
var GAP = 8;
|
|
410
452
|
function getPanelStyle(pos, offset, position) {
|
|
411
453
|
const style = {
|
|
412
454
|
...s.panel,
|
|
413
455
|
transform: `translate(${offset.x}px, ${offset.y}px)`
|
|
414
456
|
};
|
|
415
457
|
if (position.startsWith("bottom")) {
|
|
416
|
-
style.bottom = window.innerHeight - pos.top;
|
|
458
|
+
style.bottom = window.innerHeight - pos.top + GAP;
|
|
417
459
|
} else {
|
|
418
|
-
style.top = pos.top;
|
|
460
|
+
style.top = pos.top + GAP;
|
|
419
461
|
}
|
|
420
462
|
if (position.endsWith("right")) {
|
|
421
|
-
style.right = window.innerWidth - pos.left;
|
|
463
|
+
style.right = window.innerWidth - pos.left + GAP;
|
|
422
464
|
} else {
|
|
423
|
-
style.left = pos.left;
|
|
465
|
+
style.left = pos.left + GAP;
|
|
424
466
|
}
|
|
425
467
|
return style;
|
|
426
468
|
}
|
|
@@ -462,7 +504,8 @@ function DevStatsPanel({
|
|
|
462
504
|
allFrameTimes.current.push(avgFrameTime);
|
|
463
505
|
const sorted = [...allFrameTimes.current].sort((a, b) => a - b);
|
|
464
506
|
const el = targetRef.current;
|
|
465
|
-
const
|
|
507
|
+
const r = el ? getEffectiveRect(el) : null;
|
|
508
|
+
const dims = r ? `${Math.round(r.width)} x ${Math.round(r.height)}` : "\u2013";
|
|
466
509
|
const perf = performance;
|
|
467
510
|
const mem = perf.memory ? Math.round(perf.memory.usedJSHeapSize / 1024 / 1024) : 0;
|
|
468
511
|
setStats({
|
|
@@ -497,23 +540,17 @@ function DevStatsPanel({
|
|
|
497
540
|
const handleExport = (0, import_react2.useCallback)(() => {
|
|
498
541
|
const payload = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...stats };
|
|
499
542
|
const json = JSON.stringify(payload, null, 2);
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
ta.select();
|
|
512
|
-
document.execCommand("copy");
|
|
513
|
-
document.body.removeChild(ta);
|
|
514
|
-
setExported(true);
|
|
515
|
-
setTimeout(() => setExported(false), 1200);
|
|
516
|
-
}
|
|
543
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
544
|
+
const url = URL.createObjectURL(blob);
|
|
545
|
+
const a = document.createElement("a");
|
|
546
|
+
a.href = url;
|
|
547
|
+
a.download = `devprofiler-${Date.now()}.json`;
|
|
548
|
+
document.body.appendChild(a);
|
|
549
|
+
a.click();
|
|
550
|
+
document.body.removeChild(a);
|
|
551
|
+
URL.revokeObjectURL(url);
|
|
552
|
+
setExported(true);
|
|
553
|
+
setTimeout(() => setExported(false), 1200);
|
|
517
554
|
}, [stats]);
|
|
518
555
|
const ftColor = stats.frameTime > 33 ? "#ef4444" : stats.frameTime > 16.67 ? "#f59e0b" : "#4ade80";
|
|
519
556
|
const rpsColor = stats.rendersPerSecond > 30 ? "#ef4444" : stats.rendersPerSecond > 10 ? "#f59e0b" : "#4ade80";
|
|
@@ -523,36 +560,26 @@ function DevStatsPanel({
|
|
|
523
560
|
const p99Color = stats.frameTimeP99 > 33 ? "#ef4444" : stats.frameTimeP99 > 16.67 ? "#f59e0b" : "#4ade80";
|
|
524
561
|
const exportStyle = exported ? { ...s.iconBtn, ...s.iconBtnActive } : s.iconBtn;
|
|
525
562
|
return (0, import_react_dom.createPortal)(
|
|
526
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: getPanelStyle(pos, offset, position), children: [
|
|
527
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
528
|
-
"
|
|
529
|
-
|
|
530
|
-
style: s.
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25z" })
|
|
547
|
-
] })
|
|
548
|
-
}
|
|
549
|
-
),
|
|
550
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: s.iconBtn, onClick: handleReset, title: "Reset counters", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1 0-2h1.6A6 6 0 0 0 2.07 7.5a1 1 0 1 1-1.97-.36A8 8 0 0 1 13 3.35V2a1 1 0 0 1 1-1zM2 15a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h4a1 1 0 0 1 0 2H4.4A6 6 0 0 0 13.93 8.5a1 1 0 1 1 1.97.36A8 8 0 0 1 3 12.65V14a1 1 0 0 1-1 1z" }) }) }),
|
|
551
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: s.closeBtn, onClick: onClose, children: "\u2715" })
|
|
552
|
-
] })
|
|
553
|
-
]
|
|
554
|
-
}
|
|
555
|
-
),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: getPanelStyle(pos, offset, position), ...dragHandlers, children: [
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: s.panelHeader, children: [
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: s.panelTitle, children: [
|
|
566
|
+
"Dev Profiler",
|
|
567
|
+
instanceCount > 1 && instanceId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: s.instanceBadge, children: instanceId })
|
|
568
|
+
] }),
|
|
569
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: s.headerActions, children: [
|
|
570
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
571
|
+
"button",
|
|
572
|
+
{
|
|
573
|
+
style: exportStyle,
|
|
574
|
+
onClick: handleExport,
|
|
575
|
+
title: exported ? "Exported!" : "Export stats as JSON",
|
|
576
|
+
children: exported ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "3.5 8.5 6.5 11.5 12.5 4.5" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 2v8M4 7l4 4 4-4M2 14h12" }) })
|
|
577
|
+
}
|
|
578
|
+
),
|
|
579
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: s.iconBtn, onClick: handleReset, title: "Reset counters", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1 0-2h1.6A6 6 0 0 0 2.07 7.5a1 1 0 1 1-1.97-.36A8 8 0 0 1 13 3.35V2a1 1 0 0 1 1-1zM2 15a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h4a1 1 0 0 1 0 2H4.4A6 6 0 0 0 13.93 8.5a1 1 0 1 1 1.97.36A8 8 0 0 1 3 12.65V14a1 1 0 0 1-1 1z" }) }) }),
|
|
580
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: s.closeBtn, onClick: onClose, children: "\u2715" })
|
|
581
|
+
] })
|
|
582
|
+
] }),
|
|
556
583
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: s.body, children: [
|
|
557
584
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: s.section, children: "Rendering" }),
|
|
558
585
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatRow, { label: "Frame time", value: `${stats.frameTime.toFixed(1)}ms`, sub: `${fps} fps`, color: ftColor }),
|
|
@@ -599,35 +626,35 @@ function DevStatsPanel({
|
|
|
599
626
|
var import_react3 = require("react");
|
|
600
627
|
var import_react_dom2 = require("react-dom");
|
|
601
628
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
629
|
+
var GAP2 = 8;
|
|
602
630
|
function getButtonStyle(pos, position) {
|
|
603
631
|
const style = { ...s.toggleBtn };
|
|
604
632
|
if (position.startsWith("bottom")) {
|
|
605
|
-
style.bottom = window.innerHeight - pos.top +
|
|
633
|
+
style.bottom = window.innerHeight - pos.top + GAP2;
|
|
606
634
|
} else {
|
|
607
|
-
style.top = pos.top +
|
|
635
|
+
style.top = pos.top + GAP2;
|
|
608
636
|
}
|
|
609
637
|
if (position.endsWith("right")) {
|
|
610
|
-
style.right = window.innerWidth - pos.left;
|
|
638
|
+
style.right = window.innerWidth - pos.left + GAP2;
|
|
611
639
|
} else {
|
|
612
|
-
style.left = pos.left;
|
|
640
|
+
style.left = pos.left + GAP2;
|
|
613
641
|
}
|
|
614
642
|
return style;
|
|
615
643
|
}
|
|
616
644
|
function ToggleButton({
|
|
617
645
|
targetRef,
|
|
618
646
|
onClick,
|
|
619
|
-
position = "bottom-left"
|
|
647
|
+
position = "bottom-left",
|
|
648
|
+
accentColor = "#6366f1"
|
|
620
649
|
}) {
|
|
621
650
|
const pos = useAnchorPosition(targetRef, position);
|
|
622
651
|
const [fps, setFps] = (0, import_react3.useState)(0);
|
|
623
|
-
const lastFrame = (0, import_react3.useRef)(performance.now());
|
|
624
652
|
(0, import_react3.useEffect)(() => {
|
|
625
653
|
let animId;
|
|
626
654
|
let count = 0;
|
|
627
655
|
let lastSecond = performance.now();
|
|
628
656
|
const tick = () => {
|
|
629
657
|
const now = performance.now();
|
|
630
|
-
lastFrame.current = now;
|
|
631
658
|
count++;
|
|
632
659
|
if (now - lastSecond >= 1e3) {
|
|
633
660
|
setFps(count);
|
|
@@ -639,15 +666,18 @@ function ToggleButton({
|
|
|
639
666
|
animId = requestAnimationFrame(tick);
|
|
640
667
|
return () => cancelAnimationFrame(animId);
|
|
641
668
|
}, []);
|
|
642
|
-
const fpsColor = fps < 30 ? "#ef4444" : fps < 55 ? "#f59e0b" : "#4ade80";
|
|
643
669
|
return (0, import_react_dom2.createPortal)(
|
|
644
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
670
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
645
671
|
"button",
|
|
646
672
|
{
|
|
647
673
|
onClick,
|
|
648
674
|
title: "Dev Profiler (Ctrl+I)",
|
|
649
675
|
style: getButtonStyle(pos, position),
|
|
650
|
-
children:
|
|
676
|
+
children: [
|
|
677
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { ...s.toggleDot, background: accentColor, boxShadow: `0 0 4px ${accentColor}` } }),
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: s.toggleFps, children: fps }),
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: s.toggleLabel, children: "fps" })
|
|
680
|
+
]
|
|
651
681
|
}
|
|
652
682
|
),
|
|
653
683
|
document.body
|
|
@@ -672,7 +702,8 @@ var activeInstances = /* @__PURE__ */ new Set();
|
|
|
672
702
|
function DevProfiler({
|
|
673
703
|
children,
|
|
674
704
|
position = "bottom-left",
|
|
675
|
-
id
|
|
705
|
+
id,
|
|
706
|
+
accentColor = "#6366f1"
|
|
676
707
|
}) {
|
|
677
708
|
const wrapperRef = (0, import_react4.useRef)(null);
|
|
678
709
|
const [open, setOpen] = (0, import_react4.useState)(false);
|
|
@@ -712,7 +743,7 @@ function DevProfiler({
|
|
|
712
743
|
if (!__DEV__) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
|
|
713
744
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: wrapperRef, style: { display: "contents" }, children: [
|
|
714
745
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Profiler, { id: "DevProfiler", onRender, children }),
|
|
715
|
-
!open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleButton, { targetRef: wrapperRef, onClick: toggle, position }),
|
|
746
|
+
!open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleButton, { targetRef: wrapperRef, onClick: toggle, position, accentColor }),
|
|
716
747
|
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
717
748
|
DevStatsPanel,
|
|
718
749
|
{
|