import { Fiber, FiberRoot } from 'bippy'; import { ComponentType } from 'preact'; import { Signal } from '@preact/signals'; declare enum RenderPhase { Mount = 1, Update = 2, Unmount = 4 } declare const enum ChangeReason { Props = 1, FunctionalState = 2, ClassState = 3, Context = 4 } interface Render { phase: RenderPhase; componentName: string | null; time: number | null; count: number; forget: boolean; changes: Array; unnecessary: boolean | null; didCommit: boolean; fps: number; } type OnRenderHandler = (fiber: Fiber, renders: Array) => void; type OnCommitStartHandler = () => void; type OnCommitFinishHandler = () => void; type OnErrorHandler = (error: unknown) => void; type IsValidFiberHandler = (fiber: Fiber) => boolean; type OnActiveHandler = () => void; interface InstrumentationConfig { onCommitStart: OnCommitStartHandler; isValidFiber: IsValidFiberHandler; onRender: OnRenderHandler; onCommitFinish: OnCommitFinishHandler; onError: OnErrorHandler; onActive?: OnActiveHandler; onPostCommitFiberRoot: () => void; trackChanges: boolean; forceAlwaysTrackRenders?: boolean; } interface Instrumentation { isPaused: Signal; fiberRoots: WeakSet; } declare const createInstrumentation: (instanceKey: string, config: InstrumentationConfig) => Instrumentation; interface RenderData { count: number; time: number; renders: Array; displayName: string | null; type: unknown; changes?: Array; } type States = { kind: 'inspecting'; hoveredDomElement: Element | null; } | { kind: 'inspect-off'; } | { kind: 'focused'; focusedDomElement: Element; fiber: Fiber; } | { kind: 'uninitialized'; }; interface Options { /** * Enable/disable scanning * * Please use the recommended way: * enabled: process.env.NODE_ENV === 'development', * * @default true */ enabled?: boolean; /** * Force React Scan to run in production (not recommended) * * @default false */ dangerouslyForceRunInProduction?: boolean; /** * Log renders to the console * * WARNING: This can add significant overhead when the app re-renders frequently * * @default false */ log?: boolean; /** * Show toolbar bar * * If you set this to true, and set {@link enabled} to false, the toolbar will still show, but scanning will be disabled. * * @default true */ showToolbar?: boolean; /** * Animation speed * * @default "fast" */ animationSpeed?: 'slow' | 'fast' | 'off'; /** * Track unnecessary renders, and mark their outlines gray when detected * * An unnecessary render is defined as the component re-rendering with no change to the component's * corresponding dom subtree * * @default false * @warning tracking unnecessary renders can add meaningful overhead to react-scan */ trackUnnecessaryRenders?: boolean; /** * Should the FPS meter show in the toolbar * * @default true */ showFPS?: boolean; /** * Should the number of slowdown notifications be shown in the toolbar * * @default true */ showNotificationCount?: boolean; /** * Allow React Scan to run inside iframes * * @default false */ allowInIframe?: boolean; /** * Should react scan log internal errors to the console. * * Useful if react scan is not behaving expected and you want to provide information to maintainers when submitting an issue https://github.com/aidenybai/react-scan/issues * * @default false */ _debug?: 'verbose' | false; onCommitStart?: () => void; onRender?: (fiber: Fiber, renders: Array) => void; onCommitFinish?: () => void; } interface StoreType { inspectState: Signal; wasDetailsOpen: Signal; lastReportTime: Signal; isInIframe: Signal; fiberRoots: WeakSet; reportData: Map; legacyReportData: Map; changesListeners: Map>; interactionListeningForRenders: ((fiber: Fiber, renders: Array) => void) | null; } interface Internals { instrumentation: ReturnType | null; componentAllowList: WeakMap, Options> | null; options: Signal; onRender: ((fiber: Fiber, renders: Array) => void) | null; Store: StoreType; version: string; runInAllEnvironments: boolean; initToolbar?: (showToolbar: boolean) => void; addOnRenderListener?: (cb: (fiber: Fiber, renders: Array) => void) => (() => void); fiberRootsSet?: Set; } type FunctionalComponentStateChange = { type: ChangeReason.FunctionalState; value: unknown; prevValue?: unknown; count?: number | undefined; name: string; }; type ClassComponentStateChange = { type: ChangeReason.ClassState; value: unknown; prevValue?: unknown; count?: number | undefined; name: 'state'; }; type StateChange = FunctionalComponentStateChange | ClassComponentStateChange; type PropsChange = { type: ChangeReason.Props; name: string; value: unknown; prevValue?: unknown; count?: number | undefined; }; type ContextChange = { type: ChangeReason.Context; name: string; value: unknown; prevValue?: unknown; count?: number | undefined; contextType: number; }; type Change = StateChange | PropsChange | ContextChange; type ChangesPayload = { propsChanges: Array; stateChanges: Array; contextChanges: Array; }; type ChangesListener = (changes: ChangesPayload) => void; declare const ReactScanInternals: Internals; declare const setOptions: (userOptions: Partial) => { enabled?: boolean; dangerouslyForceRunInProduction?: boolean; log?: boolean; showToolbar?: boolean; animationSpeed?: "slow" | "fast" | "off"; trackUnnecessaryRenders?: boolean; showFPS?: boolean; showNotificationCount?: boolean; allowInIframe?: boolean; _debug?: "verbose" | false; onCommitStart?: () => void; onRender?: (fiber: Fiber, renders: Array) => void; onCommitFinish?: () => void; } | undefined; declare const getOptions: () => Signal; declare const scan: (options?: Options) => void; declare const useScan: (options?: Options) => void; declare const onRender: (type: unknown, _onRender: (fiber: Fiber, renders: Array) => void) => void; /** * Type definitions for React DevTools Scan integration */ interface ExtendedReactRenderer { findFiberByHostInstance: (instance: Element) => Fiber | null; version: string; bundleType: number; rendererPackageName: string; overrideHookState?: (fiber: Fiber, id: string, path: string[], value: unknown) => void; overrideProps?: (fiber: Fiber, path: string[], value: unknown) => void; overrideContext?: (fiber: Fiber, contextType: unknown, path: string[], value: unknown) => void; } declare global { interface Window { __REACT_SCAN_TOOLBAR_CONTAINER__?: HTMLDivElement; __REACT_SCAN_VERSION__?: string; __REACT_SCAN_EXTENSION__?: boolean; reactScanCleanupListeners?: (() => void); __REACT_SCAN_INTERNALS__?: any; __REACT_SCAN_STOP__?: () => void; __REACT_DEVTOOLS_GLOBAL_HOOK__?: { checkDCE: (fn: unknown) => void; supportsFiber: boolean; supportsFlight: boolean; renderers: Map; hasUnsupportedRendererAttached: boolean; onCommitFiberRoot: (rendererID: number, root: FiberRoot, priority: void | number) => void; onCommitFiberUnmount: (rendererID: number, fiber: Fiber) => void; onPostCommitFiberRoot: (rendererID: number, root: FiberRoot) => void; inject: (renderer: ExtendedReactRenderer) => number; _instrumentationSource?: string; _instrumentationIsActive?: boolean; }; } } /** * Integration modes for React Scan */ type IntegrationMode = 'overlay' | 'panel' | 'both'; /** * Extended options for React DevTools Scan integration */ interface ReactDevtoolsScanOptions extends Options { /** * Integration mode - how scan should be displayed * - 'overlay': Show as overlay on the page (default react-scan behavior) * - 'panel': Integrate into DevTools panel * - 'both': Show both overlay and panel integration * * @default 'overlay' */ integrationMode?: IntegrationMode; /** * Whether to sync state with DevTools panel * * @default true */ syncWithDevtools?: boolean; } /** * Scan instance interface */ /** * Performance metrics for a component */ interface ComponentPerformanceData { componentName: string; renderCount: number; totalTime: number; averageTime: number; unnecessaryRenders: number; lastRenderTime: number | null; } /** * Aggregated performance summary */ interface PerformanceSummary { totalRenders: number; totalComponents: number; unnecessaryRenders: number; averageRenderTime: number; slowestComponents: ComponentPerformanceData[]; } /** * Component info for selection */ interface ComponentInfo { componentName: string; fiber: any; domElement: Element | null; } /** * Change info for a single prop/state/context value */ interface ChangeInfo { name: string; previousValue: any; currentValue: any; count: number; } /** * Aggregated changes for a component render */ interface AggregatedChanges { propsChanges: ChangeInfo[]; stateChanges: ChangeInfo[]; contextChanges: ChangeInfo[]; } /** * Focused component render info with changes */ interface FocusedComponentRenderInfo { componentName: string; renderCount: number; changes: AggregatedChanges; timestamp: number; } interface ScanInstance { /** * Get current scan options */ getOptions: () => ReactDevtoolsScanOptions; /** * Update scan options at runtime */ setOptions: (options: Partial) => void; /** * Start scanning */ start: () => void; /** * Stop scanning */ stop: () => void; /** * Check if scanning is active */ isActive: () => boolean; /** * Hide the React Scan toolbar */ hideToolbar: () => void; /** * Show the React Scan toolbar */ showToolbar: () => void; /** * Get toolbar visibility state */ getToolbarVisibility: () => boolean; /** * Get performance data for all components */ getPerformanceData: () => ComponentPerformanceData[]; /** * Get aggregated performance summary */ getPerformanceSummary: () => PerformanceSummary; /** * Clear all performance data */ clearPerformanceData: () => void; /** * Start component inspection mode */ startInspecting: () => void; /** * Stop component inspection mode */ stopInspecting: () => void; /** * Check if inspection mode is active */ isInspecting: () => boolean; /** * Focus on a specific component by fiber */ focusComponent: (fiber: any) => void; /** * Get currently focused component */ getFocusedComponent: () => ComponentInfo | null; /** * Subscribe to inspection state changes */ onInspectStateChange: (callback: (state: any) => void) => () => void; /** * Get current FPS */ getFPS: () => number; /** * Get focused component render info with changes */ getFocusedComponentRenderInfo: () => FocusedComponentRenderInfo | null; /** * Subscribe to focused component changes (re-renders) */ onFocusedComponentChange: (callback: (info: FocusedComponentRenderInfo) => void) => () => void; /** * Clear the focused component's change history */ clearFocusedComponentChanges: () => void; /** * Set the focused component by name for render tracking * This is used when inspectState.kind is not 'focused' but we still want to track renders */ setFocusedComponentByName: (componentName: string) => void; /** * Get the component tree with render counts */ getComponentTree: () => ComponentTreeNode[]; /** * Clear component render count tracking */ clearComponentTree: () => void; } /** * Component tree node */ interface ComponentTreeNode { id: string; name: string; type: string; renderCount: number; lastRenderTime: number; averageTime?: number; unnecessary?: number; children: ComponentTreeNode[]; fiber?: any; } /** * React Scan Plugin for React DevTools * * This plugin integrates React Scan into the React DevTools plugin system, * providing performance monitoring and analysis capabilities. */ /** * React Scan plugin configuration */ interface ScanPluginConfig extends ReactDevtoolsScanOptions { /** * Whether to auto-start scan on plugin load * @default true */ autoStart?: boolean; } /** * Create React Scan plugin * * @param config - Plugin configuration * @returns DevTools plugin instance * * @example * ```typescript * import { createScanPlugin } from '@react-devtools-plus/scan/plugin'; * * const scanPlugin = createScanPlugin({ * enabled: true, * showToolbar: true, * autoStart: true, * }); * ``` */ declare function createScanPlugin(config?: ScanPluginConfig): any; /** * Default React Scan plugin instance */ declare const scanPlugin: any; /** * React DevTools Scan - Native scan engine integration * * @packageDocumentation */ /** * Initialize React Scan with DevTools integration * * @param options - Configuration options for React Scan * @returns Scan instance for further control * * @example * ```typescript * import { initScan } from '@react-devtools-plus/scan'; * * // Initialize with default options * const scanInstance = initScan(); * * // Initialize with custom options * const scanInstance = initScan({ * enabled: true, * showToolbar: true, * animationSpeed: 'fast', * trackUnnecessaryRenders: true, * integrationMode: 'overlay' * }); * ``` */ declare function initScan(options?: ReactDevtoolsScanOptions): ScanInstance; /** * Get the current scan instance * * @returns Current scan instance or null if not initialized * * @example * ```typescript * import { getScan } from '@react-devtools-plus/scan'; * * const scanInstance = getScan(); * if (scanInstance) { * // Check if scan is active * scanInstance.isActive(); * } * ``` */ declare function getScan(): ScanInstance | null; /** * Reset the scan instance (useful for testing) * * @example * ```typescript * import { resetScan } from '@react-devtools-plus/scan'; * * // Reset for testing * resetScan(); * ``` */ declare function resetScan(): void; export { type IntegrationMode, type Options, type ReactDevtoolsScanOptions, ReactScanInternals, type ScanInstance, type ScanPluginConfig, createScanPlugin, getOptions, getScan, initScan, onRender, resetScan, scan, scanPlugin, setOptions, useScan };