UNPKG

react-location-devtools

Version:

See https://react-location.tanstack.com/tools/devtools

536 lines (495 loc) 19.9 kB
/** * react-location-devtools * * Copyright (c) TanStack * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _extends = require('../../../node_modules/@babel/runtime/helpers/esm/extends.js'); var objectWithoutPropertiesLoose = require('../../../node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js'); var React = require('react'); var reactLocation = require('react-location'); var useLocalStorage = require('./useLocalStorage.js'); var utils = require('./utils.js'); var styledComponents = require('./styledComponents.js'); var theme = require('./theme.js'); var Explorer = require('./Explorer.js'); var Logo = require('./Logo.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var _excluded = ["style"], _excluded2 = ["style", "onClick"], _excluded3 = ["style", "onClick"], _excluded4 = ["isOpen", "setIsOpen", "handleDragStart"]; var isServer = typeof window === 'undefined'; function ReactLocationDevtools(_ref) { var initialIsOpen = _ref.initialIsOpen, _ref$panelProps = _ref.panelProps, panelProps = _ref$panelProps === void 0 ? {} : _ref$panelProps, _ref$closeButtonProps = _ref.closeButtonProps, closeButtonProps = _ref$closeButtonProps === void 0 ? {} : _ref$closeButtonProps, _ref$toggleButtonProp = _ref.toggleButtonProps, toggleButtonProps = _ref$toggleButtonProp === void 0 ? {} : _ref$toggleButtonProp, _ref$position = _ref.position, position = _ref$position === void 0 ? 'bottom-left' : _ref$position, _ref$containerElement = _ref.containerElement, Container = _ref$containerElement === void 0 ? 'footer' : _ref$containerElement; var rootRef = React__default["default"].useRef(null); var panelRef = React__default["default"].useRef(null); var _useLocalStorage = useLocalStorage["default"]('reactLocationDevtoolsOpen', initialIsOpen), isOpen = _useLocalStorage[0], setIsOpen = _useLocalStorage[1]; var _useLocalStorage2 = useLocalStorage["default"]('reactLocationDevtoolsHeight', null), devtoolsHeight = _useLocalStorage2[0], setDevtoolsHeight = _useLocalStorage2[1]; var _useSafeState = utils.useSafeState(false), isResolvedOpen = _useSafeState[0], setIsResolvedOpen = _useSafeState[1]; var _useSafeState2 = utils.useSafeState(false), isResizing = _useSafeState2[0], setIsResizing = _useSafeState2[1]; var isMounted = utils.useIsMounted(); var _handleDragStart = function handleDragStart(panelElement, startEvent) { var _panelElement$getBoun; if (startEvent.button !== 0) return; // Only allow left click for drag setIsResizing(true); var dragInfo = { originalHeight: (_panelElement$getBoun = panelElement == null ? void 0 : panelElement.getBoundingClientRect().height) != null ? _panelElement$getBoun : 0, pageY: startEvent.pageY }; var run = function run(moveEvent) { var delta = dragInfo.pageY - moveEvent.pageY; var newHeight = (dragInfo == null ? void 0 : dragInfo.originalHeight) + delta; setDevtoolsHeight(newHeight); if (newHeight < 70) { setIsOpen(false); } else { setIsOpen(true); } }; var unsub = function unsub() { setIsResizing(false); document.removeEventListener('mousemove', run); document.removeEventListener('mouseUp', unsub); }; document.addEventListener('mousemove', run); document.addEventListener('mouseup', unsub); }; React__default["default"].useEffect(function () { setIsResolvedOpen(isOpen != null ? isOpen : false); }, [isOpen, isResolvedOpen, setIsResolvedOpen]); // Toggle panel visibility before/after transition (depending on direction). // Prevents focusing in a closed panel. React__default["default"].useEffect(function () { var ref = panelRef.current; if (ref) { var handlePanelTransitionStart = function handlePanelTransitionStart() { if (ref && isResolvedOpen) { ref.style.visibility = 'visible'; } }; var handlePanelTransitionEnd = function handlePanelTransitionEnd() { if (ref && !isResolvedOpen) { ref.style.visibility = 'hidden'; } }; ref.addEventListener('transitionstart', handlePanelTransitionStart); ref.addEventListener('transitionend', handlePanelTransitionEnd); return function () { ref.removeEventListener('transitionstart', handlePanelTransitionStart); ref.removeEventListener('transitionend', handlePanelTransitionEnd); }; } }, [isResolvedOpen]); React__default["default"][isServer ? 'useEffect' : 'useLayoutEffect'](function () { if (isResolvedOpen) { var _rootRef$current, _rootRef$current$pare; var previousValue = (_rootRef$current = rootRef.current) == null ? void 0 : (_rootRef$current$pare = _rootRef$current.parentElement) == null ? void 0 : _rootRef$current$pare.style.paddingBottom; var run = function run() { var _panelRef$current, _rootRef$current2; var containerHeight = (_panelRef$current = panelRef.current) == null ? void 0 : _panelRef$current.getBoundingClientRect().height; if ((_rootRef$current2 = rootRef.current) != null && _rootRef$current2.parentElement) { rootRef.current.parentElement.style.paddingBottom = containerHeight + "px"; } }; run(); if (typeof window !== 'undefined') { window.addEventListener('resize', run); return function () { var _rootRef$current3; window.removeEventListener('resize', run); if ((_rootRef$current3 = rootRef.current) != null && _rootRef$current3.parentElement && typeof previousValue === 'string') { rootRef.current.parentElement.style.paddingBottom = previousValue; } }; } } }, [isResolvedOpen]); var _panelProps$style = panelProps.style, panelStyle = _panelProps$style === void 0 ? {} : _panelProps$style, otherPanelProps = objectWithoutPropertiesLoose["default"](panelProps, _excluded); var _closeButtonProps$sty = closeButtonProps.style, closeButtonStyle = _closeButtonProps$sty === void 0 ? {} : _closeButtonProps$sty, onCloseClick = closeButtonProps.onClick, otherCloseButtonProps = objectWithoutPropertiesLoose["default"](closeButtonProps, _excluded2); var _toggleButtonProps$st = toggleButtonProps.style, toggleButtonStyle = _toggleButtonProps$st === void 0 ? {} : _toggleButtonProps$st, onToggleClick = toggleButtonProps.onClick, otherToggleButtonProps = objectWithoutPropertiesLoose["default"](toggleButtonProps, _excluded3); // Do not render on the server if (!isMounted()) return null; return /*#__PURE__*/React__default["default"].createElement(Container, { ref: rootRef, className: "ReactLocationDevtools" }, /*#__PURE__*/React__default["default"].createElement(theme.ThemeProvider, { theme: theme.defaultTheme }, /*#__PURE__*/React__default["default"].createElement(ReactLocationDevtoolsPanel, _extends["default"]({ ref: panelRef }, otherPanelProps, { style: _extends["default"]({ position: 'fixed', bottom: '0', right: '0', zIndex: 99999, width: '100%', height: devtoolsHeight != null ? devtoolsHeight : 500, maxHeight: '90%', boxShadow: '0 0 20px rgba(0,0,0,.3)', borderTop: "1px solid " + theme.defaultTheme.gray, transformOrigin: 'top', // visibility will be toggled after transitions, but set initial state here visibility: isOpen ? 'visible' : 'hidden' }, panelStyle, isResizing ? { transition: "none" } : { transition: "all .2s ease" }, isResolvedOpen ? { opacity: 1, pointerEvents: 'all', transform: "translateY(0) scale(1)" } : { opacity: 0, pointerEvents: 'none', transform: "translateY(15px) scale(1.02)" }), isOpen: isResolvedOpen, setIsOpen: setIsOpen, handleDragStart: function handleDragStart(e) { return _handleDragStart(panelRef.current, e); } })), isResolvedOpen ? /*#__PURE__*/React__default["default"].createElement(styledComponents.Button, _extends["default"]({ type: "button", "aria-label": "Close React Location Devtools" }, otherCloseButtonProps, { onClick: function onClick(e) { setIsOpen(false); onCloseClick && onCloseClick(e); }, style: _extends["default"]({ position: 'fixed', zIndex: 99999, margin: '.5em', bottom: 0 }, position === 'top-right' ? { right: '0' } : position === 'top-left' ? { left: '0' } : position === 'bottom-right' ? { right: '0' } : { left: '0' }, closeButtonStyle) }), "Close") : null), !isResolvedOpen ? /*#__PURE__*/React__default["default"].createElement("button", _extends["default"]({ type: "button" }, otherToggleButtonProps, { "aria-label": "Open React Location Devtools", onClick: function onClick(e) { setIsOpen(true); onToggleClick && onToggleClick(e); }, style: _extends["default"]({ background: 'none', border: 0, padding: 0, position: 'fixed', zIndex: 99999, display: 'inline-flex', fontSize: '1.5em', margin: '.5em', cursor: 'pointer', width: 'fit-content' }, position === 'top-right' ? { top: '0', right: '0' } : position === 'top-left' ? { top: '0', left: '0' } : position === 'bottom-right' ? { bottom: '0', right: '0' } : { bottom: '0', left: '0' }, toggleButtonStyle) }), /*#__PURE__*/React__default["default"].createElement(Logo["default"], { "aria-hidden": true })) : null); } var ReactLocationDevtoolsPanel = /*#__PURE__*/React__default["default"].forwardRef(function ReactLocationDevtoolsPanel(props, ref) { var _router$pending; props.isOpen; props.setIsOpen; var handleDragStart = props.handleDragStart, panelProps = objectWithoutPropertiesLoose["default"](props, _excluded4); var router = reactLocation.useRouter(); var _useLocalStorage3 = useLocalStorage["default"]('reactLocationDevtoolsActiveRouteId', ''), activeMatchId = _useLocalStorage3[0], setActiveRouteId = _useLocalStorage3[1]; var activeMatch = router.state.matches.find(function (d) { return d.id === activeMatchId; }); return /*#__PURE__*/React__default["default"].createElement(theme.ThemeProvider, { theme: theme.defaultTheme }, /*#__PURE__*/React__default["default"].createElement(styledComponents.Panel, _extends["default"]({ ref: ref, className: "ReactLocationDevtoolsPanel" }, panelProps), /*#__PURE__*/React__default["default"].createElement("style", { dangerouslySetInnerHTML: { __html: "\n .ReactLocationDevtoolsPanel * {\n scrollbar-color: " + theme.defaultTheme.backgroundAlt + " " + theme.defaultTheme.gray + ";\n }\n\n .ReactLocationDevtoolsPanel *::-webkit-scrollbar, .ReactLocationDevtoolsPanel scrollbar {\n width: 1em;\n height: 1em;\n }\n\n .ReactLocationDevtoolsPanel *::-webkit-scrollbar-track, .ReactLocationDevtoolsPanel scrollbar-track {\n background: " + theme.defaultTheme.backgroundAlt + ";\n }\n\n .ReactLocationDevtoolsPanel *::-webkit-scrollbar-thumb, .ReactLocationDevtoolsPanel scrollbar-thumb {\n background: " + theme.defaultTheme.gray + ";\n border-radius: .5em;\n border: 3px solid " + theme.defaultTheme.backgroundAlt + ";\n }\n " } }), /*#__PURE__*/React__default["default"].createElement("div", { style: { position: 'absolute', left: 0, top: 0, width: '100%', height: '4px', marginBottom: '-4px', cursor: 'row-resize', zIndex: 100000 }, onMouseDown: handleDragStart }), /*#__PURE__*/React__default["default"].createElement("div", { style: { flex: '1 1 500px', minHeight: '40%', maxHeight: '100%', overflow: 'auto', borderRight: "1px solid " + theme.defaultTheme.grayAlt, display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em', background: theme.defaultTheme.backgroundAlt, display: 'flex', justifyContent: 'space-between', alignItems: 'center' } }, /*#__PURE__*/React__default["default"].createElement(Logo["default"], { "aria-hidden": true, style: { marginRight: '.5em' } }), /*#__PURE__*/React__default["default"].createElement("div", { style: { marginRight: 'auto', fontSize: 'clamp(.8rem, 2vw, 1.3rem)', fontWeight: 'bold' } }, "React Location", ' ', /*#__PURE__*/React__default["default"].createElement("span", { style: { fontWeight: 100 } }, "Devtools")), /*#__PURE__*/React__default["default"].createElement("div", { style: { display: 'flex', flexDirection: 'column' } })), /*#__PURE__*/React__default["default"].createElement("div", { style: { overflowY: 'auto', flex: '1' } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em' } }, /*#__PURE__*/React__default["default"].createElement(Explorer["default"], { label: "Location", value: router.state.location, defaultExpanded: { search: true } })), /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em' } }, /*#__PURE__*/React__default["default"].createElement(Explorer["default"], { label: "Router", value: { basepath: router.basepath, routes: router.routes, routesById: router.routesById, matchCache: router.matchCache, defaultLinkPreloadMaxAge: router.defaultLinkPreloadMaxAge, defaultLoaderMaxAge: router.defaultLoaderMaxAge, defaultPendingMinMs: router.defaultPendingMinMs, defaultPendingMs: router.defaultPendingMs, defaultElement: router.defaultElement, defaultErrorElement: router.defaultErrorElement, defaultPendingElement: router.defaultPendingElement }, defaultExpanded: {} })))), /*#__PURE__*/React__default["default"].createElement("div", { style: { flex: '1 1 500px', minHeight: '40%', maxHeight: '100%', overflow: 'auto', borderRight: "1px solid " + theme.defaultTheme.grayAlt, display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em', background: theme.defaultTheme.backgroundAlt, position: 'sticky', top: 0, zIndex: 1 } }, "Current Matches"), router.state.matches.map(function (match, i) { return /*#__PURE__*/React__default["default"].createElement("div", { key: match.id || i, role: "button", "aria-label": "Open match details for " + match.id, onClick: function onClick() { return setActiveRouteId(activeMatchId === match.id ? '' : match.id); }, style: { display: 'flex', borderBottom: "solid 1px " + theme.defaultTheme.grayAlt, cursor: 'pointer', alignItems: 'center', background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { flex: '0 0 auto', width: '1.3rem', height: '1.3rem', marginLeft: '.25rem', background: utils.getStatusColor(match, theme.defaultTheme), alignItems: 'center', justifyContent: 'center', fontWeight: 'bold', borderRadius: '.25rem', transition: 'all .2s ease-out' } }), /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, { style: { padding: '.5em' } }, "" + match.id)); }), /*#__PURE__*/React__default["default"].createElement("div", { style: { marginTop: '2rem', padding: '.5em', background: theme.defaultTheme.backgroundAlt, position: 'sticky', top: 0, zIndex: 1 } }, "Pending Matches"), (_router$pending = router.pending) == null ? void 0 : _router$pending.matches.map(function (match, i) { return /*#__PURE__*/React__default["default"].createElement("div", { key: match.id || i, role: "button", "aria-label": "Open match details for " + match.id, onClick: function onClick() { return setActiveRouteId(activeMatchId === match.id ? '' : match.id); }, style: { display: 'flex', borderBottom: "solid 1px " + theme.defaultTheme.grayAlt, cursor: 'pointer', background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { flex: '0 0 auto', width: '1.3rem', height: '1.3rem', marginLeft: '.25rem', background: utils.getStatusColor(match, theme.defaultTheme), alignItems: 'center', justifyContent: 'center', fontWeight: 'bold', borderRadius: '.25rem', transition: 'all .2s ease-out' } }), /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, { style: { padding: '.5em' } }, "" + match.id)); })), activeMatch ? /*#__PURE__*/React__default["default"].createElement(styledComponents.ActivePanel, null, /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em', background: theme.defaultTheme.backgroundAlt, position: 'sticky', top: 0, zIndex: 1 } }, "Match Details"), /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em' } }, /*#__PURE__*/React__default["default"].createElement("div", { style: { marginBottom: '.5em', display: 'flex', alignItems: 'stretch', justifyContent: 'space-between' } }, /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, { style: { lineHeight: '1.8em' } }, /*#__PURE__*/React__default["default"].createElement("pre", { style: { margin: 0, padding: 0, overflow: 'auto' } }, JSON.stringify(activeMatch.id, null, 2)))), /*#__PURE__*/React__default["default"].createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } }, "Last Updated:", ' ', activeMatch.updatedAt ? /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, null, new Date(activeMatch.updatedAt).toLocaleTimeString()) : 'N/A')), /*#__PURE__*/React__default["default"].createElement("div", { style: { background: theme.defaultTheme.backgroundAlt, padding: '.5em', position: 'sticky', top: 0, zIndex: 1 } }, "Explorer"), /*#__PURE__*/React__default["default"].createElement("div", { style: { padding: '.5em' } }, /*#__PURE__*/React__default["default"].createElement(Explorer["default"], { label: "Match", value: activeMatch, defaultExpanded: {} }))) : null)); }); exports.ReactLocationDevtools = ReactLocationDevtools; exports.ReactLocationDevtoolsPanel = ReactLocationDevtoolsPanel; //# sourceMappingURL=devtools.js.map