react-render-detective 0.5.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +2 -2
  3. package/dist/babel.cjs +2 -2
  4. package/dist/babel.d.cts +11 -0
  5. package/dist/babel.d.ts +11 -0
  6. package/dist/babel.js +1 -1
  7. package/dist/{chunk-DI5STJM4.js → chunk-3TZNM7JO.js} +66 -3
  8. package/dist/chunk-3TZNM7JO.js.map +1 -0
  9. package/dist/{chunk-HOTY7J3X.js → chunk-D7M4UC3Y.js} +26 -2
  10. package/dist/chunk-D7M4UC3Y.js.map +1 -0
  11. package/dist/{chunk-PHYYA67T.cjs → chunk-EXDRRUUQ.cjs} +69 -2
  12. package/dist/chunk-EXDRRUUQ.cjs.map +1 -0
  13. package/dist/{chunk-OSPTERGK.cjs → chunk-LCGXVRJR.cjs} +66 -3
  14. package/dist/chunk-LCGXVRJR.cjs.map +1 -0
  15. package/dist/{chunk-MCIQMYNR.js → chunk-QVHAC7AD.js} +69 -2
  16. package/dist/chunk-QVHAC7AD.js.map +1 -0
  17. package/dist/{chunk-JD4IJ4MN.cjs → chunk-RGT44QQI.cjs} +26 -2
  18. package/dist/chunk-RGT44QQI.cjs.map +1 -0
  19. package/dist/core.cjs +18 -18
  20. package/dist/core.d.cts +13 -3
  21. package/dist/core.d.ts +13 -3
  22. package/dist/core.js +1 -1
  23. package/dist/index.cjs +72 -274
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +35 -115
  26. package/dist/index.d.ts +35 -115
  27. package/dist/index.js +41 -237
  28. package/dist/index.js.map +1 -1
  29. package/dist/interactions.cjs +252 -0
  30. package/dist/interactions.cjs.map +1 -0
  31. package/dist/interactions.d.cts +110 -0
  32. package/dist/interactions.d.ts +110 -0
  33. package/dist/interactions.js +241 -0
  34. package/dist/interactions.js.map +1 -0
  35. package/dist/overlay.cjs +5 -5
  36. package/dist/overlay.js +2 -2
  37. package/dist/testing.d.cts +1 -1
  38. package/dist/testing.d.ts +1 -1
  39. package/dist/{types-gl13xwmN.d.cts → types-CRET8EhB.d.cts} +20 -2
  40. package/dist/{types-gl13xwmN.d.ts → types-CRET8EhB.d.ts} +20 -2
  41. package/dist/vite.cjs +2 -2
  42. package/dist/vite.js +1 -1
  43. package/package.json +6 -1
  44. package/dist/chunk-DI5STJM4.js.map +0 -1
  45. package/dist/chunk-HOTY7J3X.js.map +0 -1
  46. package/dist/chunk-JD4IJ4MN.cjs.map +0 -1
  47. package/dist/chunk-MCIQMYNR.js.map +0 -1
  48. package/dist/chunk-OSPTERGK.cjs.map +0 -1
  49. package/dist/chunk-PHYYA67T.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkJD4IJ4MN_cjs = require('./chunk-JD4IJ4MN.cjs');
4
- var chunkOSPTERGK_cjs = require('./chunk-OSPTERGK.cjs');
3
+ var chunkRGT44QQI_cjs = require('./chunk-RGT44QQI.cjs');
5
4
  var chunkH5RG2EPP_cjs = require('./chunk-H5RG2EPP.cjs');
5
+ var chunkLCGXVRJR_cjs = require('./chunk-LCGXVRJR.cjs');
6
6
  var React = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
 
@@ -189,7 +189,7 @@ function printVerbose(event) {
189
189
  if (event.unchangedProps.length > 0) console.log(`Props same: ${event.unchangedProps.join(", ")}`);
190
190
  if (event.trackedState.length > 0) {
191
191
  console.log(
192
- `State: ${event.trackedState.map((s) => `${s.name}: ${chunkOSPTERGK_cjs.formatInspected(s.previous)} \u2192 ${chunkOSPTERGK_cjs.formatInspected(s.current)}`).join(", ")}`
192
+ `State: ${event.trackedState.map((s) => `${s.name}: ${chunkLCGXVRJR_cjs.formatInspected(s.previous)} \u2192 ${chunkLCGXVRJR_cjs.formatInspected(s.current)}`).join(", ")}`
193
193
  );
194
194
  }
195
195
  if (event.contextChanges.length > 0) {
@@ -206,11 +206,11 @@ function printVerbose(event) {
206
206
  }
207
207
  function propLine(c) {
208
208
  const head = `${c.key} (${c.valueType}) \u2014 ${describeKind(c)}`;
209
- if (c.kind === "added") return `${head}: ${chunkOSPTERGK_cjs.formatInspected(c.current)}`;
210
- if (c.kind === "removed") return `${head}: was ${chunkOSPTERGK_cjs.formatInspected(c.previous)}`;
209
+ if (c.kind === "added") return `${head}: ${chunkLCGXVRJR_cjs.formatInspected(c.current)}`;
210
+ if (c.kind === "removed") return `${head}: was ${chunkLCGXVRJR_cjs.formatInspected(c.previous)}`;
211
211
  return `${head}
212
- previous: ${chunkOSPTERGK_cjs.formatInspected(c.previous)}
213
- current: ${chunkOSPTERGK_cjs.formatInspected(c.current)}`;
212
+ previous: ${chunkLCGXVRJR_cjs.formatInspected(c.previous)}
213
+ current: ${chunkLCGXVRJR_cjs.formatInspected(c.current)}`;
214
214
  }
215
215
  function describeKind(c) {
216
216
  switch (c.kind) {
@@ -237,6 +237,8 @@ function label(event) {
237
237
  return "context update";
238
238
  case "state":
239
239
  return "state changed";
240
+ case "store":
241
+ return "store update";
240
242
  case "state-or-external":
241
243
  return "state or external store";
242
244
  case "unknown":
@@ -244,194 +246,6 @@ function label(event) {
244
246
  }
245
247
  }
246
248
 
247
- // src/core/interactions.ts
248
- var COMMIT_SLACK_MS = 100;
249
- var FALLBACK_CLOSE_MS = 50;
250
- var InteractionTracker = class {
251
- constructor(capacity = 50) {
252
- this.capacity = capacity;
253
- this.records = [];
254
- this.nextId = 0;
255
- }
256
- /** Returns false when the browser cannot report event timing. */
257
- start() {
258
- if (this.observer) return true;
259
- const PO = globalThis.PerformanceObserver;
260
- const supported = PO?.supportedEntryTypes?.includes("event");
261
- if (!PO || !supported) return false;
262
- try {
263
- const observer = new PO((list) => {
264
- for (const entry of list.getEntries()) {
265
- const timing = entry;
266
- this.record({
267
- name: timing.name,
268
- startTime: timing.startTime,
269
- duration: timing.duration,
270
- target: describeTarget(timing.target)
271
- });
272
- }
273
- });
274
- observer.observe({ type: "event", buffered: true, durationThreshold: 16 });
275
- this.observer = observer;
276
- return true;
277
- } catch {
278
- return false;
279
- }
280
- }
281
- stop() {
282
- this.observer?.disconnect();
283
- this.observer = void 0;
284
- }
285
- /** Is the automatic path available in this browser? */
286
- get automatic() {
287
- return this.observer !== void 0;
288
- }
289
- /**
290
- * Time an interaction by hand.
291
- *
292
- * The automatic path depends on the Event Timing API, which Safari only
293
- * gained in 16.4 and which does not fire for synthetic input at all — so
294
- * anything driven by a test harness records nothing. This measures a specific
295
- * action instead, up to the paint that follows it, and needs no browser
296
- * support beyond `performance.now`.
297
- */
298
- measure(label2, action) {
299
- const startTime = now();
300
- let handlerMs = 0;
301
- let finished = false;
302
- const finish = () => {
303
- if (finished) return;
304
- finished = true;
305
- this.record({ name: label2, startTime, duration: now() - startTime, handlerMs });
306
- };
307
- let result;
308
- try {
309
- result = action();
310
- handlerMs = now() - startTime;
311
- } catch (error) {
312
- handlerMs = now() - startTime;
313
- finish();
314
- throw error;
315
- }
316
- const raf = globalThis.requestAnimationFrame;
317
- if (raf) raf(() => raf(finish));
318
- setTimeout(finish, FALLBACK_CLOSE_MS);
319
- return result;
320
- }
321
- /** Exposed for tests and for `measure`. */
322
- record(timing) {
323
- const record = {
324
- id: `interaction_${++this.nextId}`,
325
- type: timing.name,
326
- target: timing.target,
327
- startTime: timing.startTime,
328
- durationMs: timing.duration,
329
- handlerMs: timing.handlerMs,
330
- renders: [],
331
- renderTimeMs: 0,
332
- avoidableRenderTimeMs: 0
333
- };
334
- this.records.push(record);
335
- if (this.records.length > this.capacity) this.records.shift();
336
- return record;
337
- }
338
- clear() {
339
- this.records.length = 0;
340
- }
341
- /**
342
- * Joins render events to interactions by commit time. A render belongs to an
343
- * interaction when it committed between the event starting and shortly after
344
- * it finished — React commits just after the event handler returns.
345
- */
346
- attribute(events) {
347
- for (const record of this.records) {
348
- const from = record.startTime;
349
- const to = record.startTime + record.durationMs + COMMIT_SLACK_MS;
350
- record.renders = events.filter((e) => e.timings.commitTime >= from && e.timings.commitTime <= to);
351
- record.renderTimeMs = record.renders.reduce((a, e) => a + e.timings.selfDuration, 0);
352
- record.avoidableRenderTimeMs = record.renders.filter((e) => e.diagnosis.potentiallyAvoidable).reduce((a, e) => a + e.timings.selfDuration, 0);
353
- }
354
- return [...this.records].sort((a, b) => b.durationMs - a.durationMs);
355
- }
356
- };
357
- function summarise(record) {
358
- const byComponent = /* @__PURE__ */ new Map();
359
- for (const event of record.renders) {
360
- const entry = byComponent.get(event.component.name) ?? {
361
- renders: 0,
362
- totalMs: 0,
363
- source: event.component.source,
364
- cause: event.diagnosis.reason
365
- };
366
- entry.renders++;
367
- entry.totalMs += event.timings.selfDuration;
368
- byComponent.set(event.component.name, entry);
369
- }
370
- const contributors = [...byComponent.entries()].map(([component, v]) => ({ component, source: v.source, renders: v.renders, totalMs: v.totalMs, cause: v.cause })).sort((a, b) => b.totalMs - a.totalMs);
371
- const top = contributors[0];
372
- const accounted = (record.handlerMs ?? record.durationMs) + record.renderTimeMs;
373
- const idleWindow = record.handlerMs !== void 0 && record.durationMs > accounted * 3 && record.durationMs - accounted > 100;
374
- const effectiveMs = idleWindow ? accounted : record.durationMs;
375
- const share = effectiveMs > 0 ? record.renderTimeMs / effectiveMs : 0;
376
- let headline;
377
- let nextStep;
378
- let confidence = "medium";
379
- if (idleWindow) {
380
- headline = `${record.type}: ${fmt(record.handlerMs ?? 0)} in the handler and ${fmt(record.renderTimeMs)} rendering. The measured window was ${fmt(record.durationMs)}, but most of that was the page waiting for a frame \u2014 ignore it.`;
381
- nextStep = record.renderTimeMs > (record.handlerMs ?? 0) ? `Rendering dominates the real work${top ? `; start with ${top.component}` : ""}.` : "The handler itself costs more than rendering. Profile the handler, not React.";
382
- return { interaction: record, contributors, headline, nextStep, confidence: "medium" };
383
- }
384
- if (record.renders.length === 0) {
385
- headline = `${record.type} took ${fmt(record.durationMs)}, and no instrumented component rendered inside it.`;
386
- nextStep = "The cost is somewhere other than React rendering \u2014 an event handler, a layout, or an uninstrumented component. Instrument more of the tree to narrow it down.";
387
- confidence = "low";
388
- } else if (share >= 0.4 && record.avoidableRenderTimeMs > 0) {
389
- headline = `${record.type} took ${fmt(record.durationMs)}; ${fmt(record.renderTimeMs)} of it was rendering, and ${fmt(record.avoidableRenderTimeMs)} of that had no input change to explain it.`;
390
- nextStep = top ? `Start with ${top.component}${top.source ? ` (${top.source})` : ""} \u2014 ${fmt(top.totalMs)} across ${top.renders} render${top.renders === 1 ? "" : "s"}.` : "Look at the top contributor below.";
391
- confidence = "high";
392
- } else if (share >= 0.4) {
393
- headline = `${record.type} took ${fmt(record.durationMs)}; ${fmt(record.renderTimeMs)} of it was rendering, all of it explained by real input changes.`;
394
- nextStep = "This is genuine work. Make the renders cheaper rather than fewer \u2014 or do less of it per interaction.";
395
- confidence = "high";
396
- } else {
397
- headline = `${record.type} took ${fmt(record.durationMs)}, but only ${fmt(record.renderTimeMs)} was React rendering.`;
398
- nextStep = "Most of the cost is outside rendering \u2014 event handlers, layout or paint. A browser profile will show more than this tool can.";
399
- confidence = "medium";
400
- }
401
- return { interaction: record, contributors, headline, nextStep, confidence };
402
- }
403
- function formatInteraction(summary) {
404
- const { interaction: i } = summary;
405
- const lines = [
406
- `${i.type}${i.target ? ` on ${i.target}` : ""} ${fmt(i.durationMs)}`,
407
- "",
408
- summary.headline
409
- ];
410
- if (summary.contributors.length > 0) {
411
- lines.push("", "Rendering inside this interaction");
412
- for (const c of summary.contributors.slice(0, 8)) {
413
- lines.push(
414
- ` ${c.component.padEnd(22)} ${String(c.renders).padStart(4)} render(s) ${fmt(c.totalMs).padStart(8)} ${c.cause}`
415
- );
416
- }
417
- }
418
- lines.push("", `Next step`, ` ${summary.nextStep}`, "", `Confidence: ${summary.confidence}`);
419
- return lines.join("\n");
420
- }
421
- function describeTarget(target) {
422
- if (!target || typeof target !== "object") return void 0;
423
- const el = target;
424
- if (!el.tagName) return void 0;
425
- const tag = el.tagName.toLowerCase();
426
- if (el.id) return `${tag}#${el.id}`;
427
- const className = typeof el.className === "string" ? el.className.trim().split(/\s+/)[0] : void 0;
428
- if (className) return `${tag}.${className}`;
429
- const text = el.textContent?.trim().slice(0, 20);
430
- return text ? `${tag} "${text}"` : tag;
431
- }
432
- var fmt = (ms) => `${ms.toFixed(1)}ms`;
433
- var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
434
-
435
249
  // src/core/opportunities.ts
436
250
  var DEFAULT_MIN_SAVING_MS = 1;
437
251
  function rankOpportunities({ events, lifecycles, minSavingMs = DEFAULT_MIN_SAVING_MS }) {
@@ -439,7 +253,7 @@ function rankOpportunities({ events, lifecycles, minSavingMs = DEFAULT_MIN_SAVIN
439
253
  const out = [];
440
254
  for (const name of names) {
441
255
  const lifecycle = lifecycles.get(name);
442
- const explanation = chunkJD4IJ4MN_cjs.explainEvents(name, events, lifecycle);
256
+ const explanation = chunkRGT44QQI_cjs.explainEvents(name, events, lifecycle);
443
257
  if (!explanation) continue;
444
258
  const mounts = events.filter((e) => e.component.name === name && e.phase === "mount");
445
259
  const averageMountCost = mounts.length ? mounts.reduce((a, e) => a + e.timings.selfDuration, 0) / mounts.length : 0;
@@ -485,7 +299,7 @@ function formatOpportunities(opportunities) {
485
299
  var AncestryContext = React.createContext(void 0);
486
300
  AncestryContext.displayName = "RenderDetectiveAncestry";
487
301
  function useInstrumentedNode(name, props, source) {
488
- const detective = chunkOSPTERGK_cjs.getDetective();
302
+ const detective = chunkLCGXVRJR_cjs.getDetective();
489
303
  const parent = React.useContext(AncestryContext);
490
304
  const [node] = React.useState(
491
305
  () => detective.enabled ? detective.createNode(name, parent, source) : void 0
@@ -535,7 +349,7 @@ var IS_WRAPPER = /* @__PURE__ */ Symbol.for("react-render-detective.wrapper");
535
349
  function withRenderDetective(Component, options = {}) {
536
350
  if (Component[IS_WRAPPER]) return Component;
537
351
  const name = options.name ?? componentName(Component);
538
- chunkOSPTERGK_cjs.getDetective().noteDefinition(name, options.source, options.declaredInRender === true);
352
+ chunkLCGXVRJR_cjs.getDetective().noteDefinition(name, options.source, options.declaredInRender === true);
539
353
  function RenderDetected(props) {
540
354
  const { node, onRender } = useInstrumentedNode(name, props, options.source);
541
355
  return renderInstrumented(node, onRender, /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props }));
@@ -550,8 +364,40 @@ function RenderDetective({ name, children }) {
550
364
  const { node, onRender } = useInstrumentedNode(name, { children });
551
365
  return renderInstrumented(node, onRender, children);
552
366
  }
367
+ var useOwnerId = typeof React__namespace.useId === "function" ? React__namespace.useId : () => "";
368
+ function trackSelector(value, options = {}) {
369
+ const detective = chunkLCGXVRJR_cjs.getDetective();
370
+ const node = React.useContext(AncestryContext);
371
+ const ownerId = useOwnerId();
372
+ const previous = React.useRef(void 0);
373
+ if (!detective.enabled) return value;
374
+ if (node && node.stateOwner === void 0) node.stateOwner = ownerId;
375
+ const owns = !node || node.stateOwner === ownerId;
376
+ const prior = previous.current;
377
+ previous.current = { value };
378
+ if (!prior || !node || !owns) return value;
379
+ if (Object.is(prior.value, value)) return value;
380
+ try {
381
+ const equal = chunkLCGXVRJR_cjs.shallowEqual(prior.value, value, detective.config);
382
+ detective.recordSelectorChange(node, {
383
+ name: options.name ?? options.source ?? "selector",
384
+ source: options.source,
385
+ referenceOnly: equal === true,
386
+ previous: chunkLCGXVRJR_cjs.inspect(prior.value, detective.config.inspection),
387
+ current: chunkLCGXVRJR_cjs.inspect(value, detective.config.inspection)
388
+ });
389
+ } catch {
390
+ }
391
+ return value;
392
+ }
393
+ function createTrackedSelectorHook(hook, options = {}) {
394
+ return function useTrackedSelector(...args) {
395
+ const value = hook(...args);
396
+ return trackSelector(value, options);
397
+ };
398
+ }
553
399
  function useRenderDiagnostics(name, props) {
554
- const detective = chunkOSPTERGK_cjs.getDetective();
400
+ const detective = chunkLCGXVRJR_cjs.getDetective();
555
401
  const parent = React.useContext(AncestryContext);
556
402
  const [node] = React.useState(() => {
557
403
  if (!detective.enabled) return void 0;
@@ -584,11 +430,11 @@ function useRenderDiagnostics(name, props) {
584
430
  }
585
431
  return last.current;
586
432
  }
587
- var useOwnerId = typeof React__namespace.useId === "function" ? React__namespace.useId : () => "";
433
+ var useOwnerId2 = typeof React__namespace.useId === "function" ? React__namespace.useId : () => "";
588
434
  function useTrackedState(name, initial) {
589
- const detective = chunkOSPTERGK_cjs.getDetective();
435
+ const detective = chunkLCGXVRJR_cjs.getDetective();
590
436
  const node = React.useContext(AncestryContext);
591
- const ownerId = useOwnerId();
437
+ const ownerId = useOwnerId2();
592
438
  const [state, setState] = React.useState(initial);
593
439
  const previous = React.useRef(state);
594
440
  if (node && node.stateOwner === void 0) node.stateOwner = ownerId;
@@ -596,8 +442,8 @@ function useTrackedState(name, initial) {
596
442
  if (node && owns && !Object.is(previous.current, state)) {
597
443
  detective.recordStateChange(node, {
598
444
  name,
599
- previous: chunkOSPTERGK_cjs.inspect(previous.current, detective.config.inspection),
600
- current: chunkOSPTERGK_cjs.inspect(state, detective.config.inspection)
445
+ previous: chunkLCGXVRJR_cjs.inspect(previous.current, detective.config.inspection),
446
+ current: chunkLCGXVRJR_cjs.inspect(state, detective.config.inspection)
601
447
  });
602
448
  previous.current = state;
603
449
  } else if (!owns) {
@@ -606,7 +452,7 @@ function useTrackedState(name, initial) {
606
452
  return [state, setState];
607
453
  }
608
454
  function useTrackedEffect(name, effect, deps) {
609
- const detective = chunkOSPTERGK_cjs.getDetective();
455
+ const detective = chunkLCGXVRJR_cjs.getDetective();
610
456
  const previous = React.useRef(void 0);
611
457
  const changed = React.useRef([]);
612
458
  if (detective.enabled) {
@@ -622,7 +468,7 @@ function useTrackedEffect(name, effect, deps) {
622
468
  }, deps);
623
469
  }
624
470
  function useTrackedContextValue(contextName, value) {
625
- const detective = chunkOSPTERGK_cjs.getDetective();
471
+ const detective = chunkLCGXVRJR_cjs.getDetective();
626
472
  const previous = React.useRef(void 0);
627
473
  const first = React.useRef(true);
628
474
  if (detective.enabled) {
@@ -630,8 +476,8 @@ function useTrackedContextValue(contextName, value) {
630
476
  first.current = false;
631
477
  } else if (!Object.is(previous.current, value)) {
632
478
  const prev = previous.current;
633
- const equal = chunkOSPTERGK_cjs.shallowEqual(prev, value, detective.config);
634
- const changedKeys = isRecord(prev) && isRecord(value) ? chunkOSPTERGK_cjs.diffProps(prev, value, detective.config).changed.map((c) => c.key) : [];
479
+ const equal = chunkLCGXVRJR_cjs.shallowEqual(prev, value, detective.config);
480
+ const changedKeys = isRecord(prev) && isRecord(value) ? chunkLCGXVRJR_cjs.diffProps(prev, value, detective.config).changed.map((c) => c.key) : [];
635
481
  detective.recordContextChange({
636
482
  contextName,
637
483
  changedKeys,
@@ -649,21 +495,12 @@ function isRecord(v) {
649
495
 
650
496
  // src/index.ts
651
497
  var REPORTER = /* @__PURE__ */ Symbol.for("react-render-detective.reporter");
652
- var INTERACTIONS = /* @__PURE__ */ Symbol.for("react-render-detective.interactions");
653
- function tracker() {
654
- const g = globalThis;
655
- if (!g[INTERACTIONS]) g[INTERACTIONS] = new InteractionTracker();
656
- return g[INTERACTIONS];
657
- }
658
498
  function init(options = {}) {
659
- const detective = chunkOSPTERGK_cjs.getDetective();
499
+ const detective = chunkLCGXVRJR_cjs.getDetective();
660
500
  detective.init(options);
661
501
  const g = globalThis;
662
502
  g[REPORTER]?.();
663
503
  g[REPORTER] = void 0;
664
- if (detective.enabled) {
665
- tracker().start();
666
- }
667
504
  if (detective.enabled && detective.config.mode !== "silent") {
668
505
  g[REPORTER] = attachConsoleReporter(detective);
669
506
  } else if (!detective.enabled) {
@@ -673,77 +510,49 @@ function init(options = {}) {
673
510
  }
674
511
  }
675
512
  function configure(options) {
676
- chunkOSPTERGK_cjs.getDetective().configure(options);
513
+ chunkLCGXVRJR_cjs.getDetective().configure(options);
677
514
  }
678
515
  function getConfig() {
679
- return chunkOSPTERGK_cjs.getDetective().config;
516
+ return chunkLCGXVRJR_cjs.getDetective().config;
680
517
  }
681
518
  function isEnabled() {
682
- return chunkOSPTERGK_cjs.getDetective().enabled;
519
+ return chunkLCGXVRJR_cjs.getDetective().enabled;
683
520
  }
684
521
  function getEvents() {
685
- return chunkOSPTERGK_cjs.getDetective().getEvents();
522
+ return chunkLCGXVRJR_cjs.getDetective().getEvents();
686
523
  }
687
524
  function getStats() {
688
- return chunkOSPTERGK_cjs.getDetective().getStats();
525
+ return chunkLCGXVRJR_cjs.getDetective().getStats();
689
526
  }
690
527
  function getComponentStats(name) {
691
- return chunkOSPTERGK_cjs.getDetective().getComponentStats(name);
528
+ return chunkLCGXVRJR_cjs.getDetective().getComponentStats(name);
692
529
  }
693
530
  function subscribe(listener) {
694
- return chunkOSPTERGK_cjs.getDetective().subscribe(listener);
531
+ return chunkLCGXVRJR_cjs.getDetective().subscribe(listener);
695
532
  }
696
533
  function clear() {
697
- chunkOSPTERGK_cjs.getDetective().clear();
698
- tracker().clear();
534
+ chunkLCGXVRJR_cjs.getDetective().clear();
699
535
  }
700
536
  function reset() {
701
537
  const g = globalThis;
702
538
  g[REPORTER]?.();
703
539
  g[REPORTER] = void 0;
704
- g[INTERACTIONS]?.stop();
705
- g[INTERACTIONS] = void 0;
706
- chunkOSPTERGK_cjs.getDetective().reset();
540
+ chunkLCGXVRJR_cjs.getDetective().reset();
707
541
  }
708
542
  function explain(componentName2) {
709
543
  const explanation = explainStructured(componentName2);
710
- return explanation ? chunkJD4IJ4MN_cjs.formatExplanation(explanation) : void 0;
544
+ return explanation ? chunkRGT44QQI_cjs.formatExplanation(explanation) : void 0;
711
545
  }
712
546
  function explainStructured(componentName2) {
713
- return chunkJD4IJ4MN_cjs.explainEvents(componentName2, getEvents(), chunkOSPTERGK_cjs.getDetective().lifecycleOf(componentName2));
547
+ return chunkRGT44QQI_cjs.explainEvents(componentName2, getEvents(), chunkLCGXVRJR_cjs.getDetective().lifecycleOf(componentName2));
714
548
  }
715
549
  function getRenderProfile(scenario) {
716
550
  const remounts = {};
717
- for (const stats of chunkOSPTERGK_cjs.getDetective().getComponentStats()) remounts[stats.name] = stats.remountCount;
551
+ for (const stats of chunkLCGXVRJR_cjs.getDetective().getComponentStats()) remounts[stats.name] = stats.remountCount;
718
552
  return chunkH5RG2EPP_cjs.profileFromEvents(scenario, getEvents(), remounts);
719
553
  }
720
- function getInteractions() {
721
- return tracker().attribute(getEvents());
722
- }
723
- function explainInteractionStructured(id) {
724
- const records = getInteractions();
725
- const record = id ? records.find((r) => r.id === id) : records[0];
726
- return record ? summarise(record) : void 0;
727
- }
728
- function explainInteraction(id) {
729
- const summary = explainInteractionStructured(id);
730
- return summary ? formatInteraction(summary) : void 0;
731
- }
732
- function printInteractions(limit = 5) {
733
- const records = getInteractions().slice(0, limit);
734
- if (records.length === 0) {
735
- console.log(
736
- tracker().automatic ? "No interactions recorded yet. Event timing is working \u2014 nothing has taken longer than 16ms.\nSynthetic clicks from a test harness never produce these entries; use measureInteraction() there." : "This browser does not report event timing (Safari before 16.4, jsdom).\nUse measureInteraction(label, fn) to time interactions by hand."
737
- );
738
- return;
739
- }
740
- console.log(records.map((r) => formatInteraction(summarise(r))).join("\n\n"));
741
- }
742
- function measureInteraction(label2, action) {
743
- return tracker().measure(label2, action);
744
- }
745
554
  function getOpportunities(limit = 10) {
746
- const detective = chunkOSPTERGK_cjs.getDetective();
555
+ const detective = chunkLCGXVRJR_cjs.getDetective();
747
556
  const lifecycles = /* @__PURE__ */ new Map();
748
557
  for (const stats of detective.getComponentStats()) {
749
558
  lifecycles.set(stats.name, { remounts: stats.remountCount });
@@ -800,51 +609,40 @@ var ReactRenderDetective = {
800
609
  explainStructured,
801
610
  getOpportunities,
802
611
  printOpportunities,
803
- getInteractions,
804
- explainInteraction,
805
- explainInteractionStructured,
806
- printInteractions,
807
- measureInteraction,
808
612
  getRenderProfile,
809
613
  printStats
810
614
  };
811
615
 
812
616
  Object.defineProperty(exports, "explainEvents", {
813
617
  enumerable: true,
814
- get: function () { return chunkJD4IJ4MN_cjs.explainEvents; }
618
+ get: function () { return chunkRGT44QQI_cjs.explainEvents; }
815
619
  });
816
620
  Object.defineProperty(exports, "formatExplanation", {
817
621
  enumerable: true,
818
- get: function () { return chunkJD4IJ4MN_cjs.formatExplanation; }
622
+ get: function () { return chunkRGT44QQI_cjs.formatExplanation; }
819
623
  });
820
- exports.InteractionTracker = InteractionTracker;
821
624
  exports.ReactRenderDetective = ReactRenderDetective;
822
625
  exports.RenderDetective = RenderDetective;
823
626
  exports.clear = clear;
824
627
  exports.configure = configure;
628
+ exports.createTrackedSelectorHook = createTrackedSelectorHook;
825
629
  exports.explain = explain;
826
- exports.explainInteraction = explainInteraction;
827
- exports.explainInteractionStructured = explainInteractionStructured;
828
630
  exports.explainStructured = explainStructured;
829
- exports.formatInteraction = formatInteraction;
830
631
  exports.formatOpportunities = formatOpportunities;
831
632
  exports.getComponentStats = getComponentStats;
832
633
  exports.getConfig = getConfig;
833
634
  exports.getEvents = getEvents;
834
- exports.getInteractions = getInteractions;
835
635
  exports.getOpportunities = getOpportunities;
836
636
  exports.getRenderProfile = getRenderProfile;
837
637
  exports.getStats = getStats;
838
638
  exports.init = init;
839
639
  exports.isEnabled = isEnabled;
840
- exports.measureInteraction = measureInteraction;
841
- exports.printInteractions = printInteractions;
842
640
  exports.printOpportunities = printOpportunities;
843
641
  exports.printStats = printStats;
844
642
  exports.rankOpportunities = rankOpportunities;
845
643
  exports.reset = reset;
846
644
  exports.subscribe = subscribe;
847
- exports.summariseInteraction = summarise;
645
+ exports.trackSelector = trackSelector;
848
646
  exports.useRenderDiagnostics = useRenderDiagnostics;
849
647
  exports.useTrackedContextValue = useTrackedContextValue;
850
648
  exports.useTrackedEffect = useTrackedEffect;