react-dev-inspector
Version:
dev-tool for inspect react components and jump to local IDE for component code.
132 lines (131 loc) • 5.42 kB
JavaScript
'use client';
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
import { useState, useEffect, useRef, } from 'react';
import hotkeys from 'hotkeys-js';
import { setupHighlighter, getElementCodeInfo, gotoServerEditor, getElementInspect, } from './utils';
import { useLayoutEffect, useEffectEvent, useMousePosition, } from './hooks';
import { Overlay } from './Overlay';
/**
* `v2.0.0` changes:
* - make 'Ctrl + Shift + Alt + C' as default shortcut on Windows/Linux
* - export `defaultHotkeys`
*/
export const defaultHotkeys = () => {
var _a;
return ((_a = navigator.platform) === null || _a === void 0 ? void 0 : _a.startsWith('Mac'))
? ['Ctrl', 'Shift', 'Command', 'C']
: ['Ctrl', 'Shift', 'Alt', 'C'];
};
export const Inspector = (props) => {
const { keys, onHoverElement, onClickElement, onInspectElement, active: controlledActive, onActiveChange, disableLaunchEditor, disable = (process.env.NODE_ENV !== 'development'), children, } = props;
const [isActive, setActive] = useState(controlledActive !== null && controlledActive !== void 0 ? controlledActive : false);
// sync state as controlled component
useLayoutEffect(() => {
if (controlledActive !== undefined) {
setActive(controlledActive);
}
}, [controlledActive]);
useEffect(() => {
isActive
? startInspect()
: stopInspect();
return stopInspect;
}, [isActive]);
// hotkeys-js params need string
const hotkey = keys === null
? null
: (keys !== null && keys !== void 0 ? keys : []).join('+');
/** inspector tooltip overlay */
const overlayRef = useRef();
const mouseRef = useMousePosition({ disable });
const activate = useEffectEvent(() => {
onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(true);
if (controlledActive === undefined) {
setActive(true);
}
});
const deactivate = useEffectEvent(() => {
onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(false);
if (controlledActive === undefined) {
setActive(false);
}
});
const startInspect = useEffectEvent(() => {
if (overlayRef.current || disable)
return;
const overlay = new Overlay();
overlayRef.current = overlay;
hotkeys(`esc`, deactivate);
const stopCallback = setupHighlighter({
onPointerOver: handleHoverElement,
onClick: handleClickElement,
});
overlay.setRemoveCallback(stopCallback);
// inspect element immediately at mouse point
const initPoint = mouseRef.current;
const initElement = document.elementFromPoint(initPoint.x, initPoint.y);
if (initElement)
handleHoverElement(initElement);
});
const stopInspect = useEffectEvent(() => {
var _a;
(_a = overlayRef.current) === null || _a === void 0 ? void 0 : _a.remove();
overlayRef.current = undefined;
hotkeys.unbind(`esc`, deactivate);
});
const handleHoverElement = useEffectEvent((element) => {
var _a;
const overlay = overlayRef.current;
const codeInfo = getElementCodeInfo(element);
const relativePath = codeInfo === null || codeInfo === void 0 ? void 0 : codeInfo.relativePath;
const absolutePath = codeInfo === null || codeInfo === void 0 ? void 0 : codeInfo.absolutePath;
const { fiber, name, title } = getElementInspect(element);
(_a = overlay === null || overlay === void 0 ? void 0 : overlay.inspect) === null || _a === void 0 ? void 0 : _a.call(overlay, [element], title, relativePath !== null && relativePath !== void 0 ? relativePath : absolutePath);
onHoverElement === null || onHoverElement === void 0 ? void 0 : onHoverElement({
element,
fiber,
codeInfo,
name,
});
});
const handleClickElement = useEffectEvent((element) => {
deactivate();
const codeInfo = getElementCodeInfo(element);
const { fiber, name } = getElementInspect(element);
onClickElement === null || onClickElement === void 0 ? void 0 : onClickElement({
element,
fiber,
codeInfo,
name,
});
if (fiber && codeInfo) {
onInspectElement === null || onInspectElement === void 0 ? void 0 : onInspectElement({
element,
fiber,
codeInfo,
name: name,
});
if (!onInspectElement && !disableLaunchEditor) {
gotoServerEditor(codeInfo);
}
}
});
useEffect(() => {
const handleHotKeys = () => {
overlayRef.current
? deactivate()
: activate();
};
const bindKey = (hotkey === null || disable)
? null
: (hotkey || defaultHotkeys().join('+'));
if (bindKey) {
// https://github.com/jaywcjlove/hotkeys
hotkeys(bindKey, handleHotKeys);
return () => {
hotkeys.unbind(bindKey, handleHotKeys);
};
}
}, [hotkey, disable]);
return (_jsx(_Fragment, { children: children !== null && children !== void 0 ? children : null }));
};