@djangocfg/debuger 2.1.356 → 2.1.357

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.
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { useMemo, useState, useEffect } from 'react';
3
+ import React, { memo, useMemo, useState, useEffect } from 'react';
4
4
  import { installMonitorBridge } from './bridges';
5
5
  import { MONITOR_VERSION } from '@djangocfg/monitor/client';
6
6
  import {
@@ -61,7 +61,14 @@ const POSITION_CLASSES: Record<NonNullable<DebugPanelProps['position']>, string>
61
61
  // Component
62
62
  // ============================================================================
63
63
 
64
- export function DebugPanel({
64
+ /**
65
+ * DebugPanel — floating debug panel with tabs (logs, audio, custom).
66
+ *
67
+ * Memoised: re-renders only when `tabs`, `position`, `defaultHeight`
68
+ * or `defaultWidth` change. `tabs` array is compared by reference —
69
+ * consumers should define it outside the component or memoise it.
70
+ */
71
+ function DebugPanelRaw({
65
72
  tabs: customTabs = [],
66
73
  position = 'bottom-left',
67
74
  defaultHeight = 480,
@@ -171,3 +178,5 @@ export function DebugPanel({
171
178
  </div>
172
179
  );
173
180
  }
181
+
182
+ export const DebugPanel = memo(DebugPanelRaw);
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { useCallback, useState } from 'react';
3
+ import React, { memo, useCallback, useState } from 'react';
4
4
  import {
5
5
  Button,
6
6
  Badge,
@@ -57,7 +57,13 @@ interface AudioDebugPanelProps {
57
57
  isActive: boolean;
58
58
  }
59
59
 
60
- export function AudioDebugPanel({ isActive }: AudioDebugPanelProps) {
60
+ /**
61
+ * AudioDebugPanel — real-time audio event log with metrics.
62
+ *
63
+ * Memoised: re-renders only when `isActive` changes. Internal event
64
+ * log state is managed by the hook and does not break memoisation.
65
+ */
66
+ function AudioDebugPanelRaw({ isActive }: AudioDebugPanelProps) {
61
67
  const { events, clear, seekRate, syncIntervalMs, kindCounts } = useAudioEventLog(isActive);
62
68
  const [debugMode, setDebugMode] = useState<DebugAudioMode>(getDebugAudioMode);
63
69
 
@@ -155,3 +161,5 @@ export function AudioDebugPanel({ isActive }: AudioDebugPanelProps) {
155
161
  </div>
156
162
  );
157
163
  }
164
+
165
+ export const AudioDebugPanel = memo(AudioDebugPanelRaw);
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { useState, useCallback, useEffect, useRef } from 'react';
3
+ import React, { memo, useState, useCallback, useEffect, useRef } from 'react';
4
4
  import {
5
5
  useDebugLogStore,
6
6
  useDebugFilteredLogs,
@@ -53,7 +53,13 @@ interface LogEntryRowProps {
53
53
  onToggle: () => void;
54
54
  }
55
55
 
56
- function LogEntryRow({ entry, expanded, onToggle }: LogEntryRowProps) {
56
+ /**
57
+ * LogEntryRow — single virtualised log entry.
58
+ *
59
+ * Memoised: re-renders only when `entry` reference, `expanded`, or
60
+ * `onToggle` reference change. `entry` is treated as immutable.
61
+ */
62
+ const LogEntryRow = memo(function LogEntryRow({ entry, expanded, onToggle }: LogEntryRowProps) {
57
63
  const config = LOG_LEVEL_CONFIG[entry.level];
58
64
  const Icon = config.icon;
59
65
  const pad = (n: number, len = 2) => String(n).padStart(len, '0');
@@ -96,13 +102,20 @@ function LogEntryRow({ entry, expanded, onToggle }: LogEntryRowProps) {
96
102
  )}
97
103
  </div>
98
104
  );
99
- }
105
+ });
100
106
 
101
107
  // ============================================================================
102
108
  // LogsPanel
103
109
  // ============================================================================
104
110
 
105
- export function LogsPanel({ isActive }: { isActive: boolean }) {
111
+ /**
112
+ * LogsPanel — virtualised log viewer with filters and search.
113
+ *
114
+ * Memoised: re-renders only when `isActive` changes. Internal filter
115
+ * state and log store subscriptions are isolated and do not propagate
116
+ * to parent components.
117
+ */
118
+ function LogsPanelRaw({ isActive }: { isActive: boolean }) {
106
119
  const [expandedLogs, setExpandedLogs] = useState<Set<string>>(new Set());
107
120
  const [searchQuery, setSearchQuery] = useState('');
108
121
  const [selectedLevels, setSelectedLevels] = useState<Set<LogLevel>>(
@@ -265,3 +278,5 @@ export function LogsPanel({ isActive }: { isActive: boolean }) {
265
278
  </div>
266
279
  );
267
280
  }
281
+
282
+ export const LogsPanel = memo(LogsPanelRaw);
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React from 'react';
3
+ import React, { memo } from 'react';
4
4
  import { ScrollArea } from '@djangocfg/ui-core/components';
5
5
  import { LazyJsonTree } from '@djangocfg/ui-tools';
6
6
  import { Database } from 'lucide-react';
@@ -48,8 +48,12 @@ export interface StorePanelProps {
48
48
  * getState={() => useTimelineStore.getState()}
49
49
  * isActive={isActive}
50
50
  * />
51
+ *
52
+ * Memoised: re-renders only when `label`, `getState`, `intervalMs` or
53
+ * `isActive` change. `getState` is compared by reference — callers should
54
+ * stabilise it (e.g. define outside the component or wrap in useCallback).
51
55
  */
52
- export function StorePanel({ label, getState, intervalMs = 200, isActive }: StorePanelProps) {
56
+ function StorePanelRaw({ label, getState, intervalMs = 200, isActive }: StorePanelProps) {
53
57
  const snapshot = useStoreSnapshot(getState, intervalMs, isActive);
54
58
 
55
59
  return (
@@ -69,3 +73,5 @@ export function StorePanel({ label, getState, intervalMs = 200, isActive }: Stor
69
73
  </div>
70
74
  );
71
75
  }
76
+
77
+ export const StorePanel = memo(StorePanelRaw);