UNPKG

manipulative

Version:

React devtool for modifying Emotion styles in browser

345 lines (306 loc) 12.6 kB
import { jsxs, jsx } from '@emotion/react/jsx-runtime'; import { css } from '@emotion/react'; import { useRef, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import create from 'zustand'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; } var _ref = process.env.NODE_ENV === "production" ? { name: "1nibbwx", styles: "background-color:#f0f0f0;color:#808080;padding:8px 12px;font-size:10px;letter-spacing:0.2px;text-transform:uppercase;user-select:none;cursor:move" } : { name: "gjt1qk-Pane", styles: "background-color:#f0f0f0;color:#808080;padding:8px 12px;font-size:10px;letter-spacing:0.2px;text-transform:uppercase;user-select:none;cursor:move;label:Pane;", toString: _EMOTION_STRINGIFIED_CSS_ERROR__ }; var _ref2 = process.env.NODE_ENV === "production" ? { name: "15ef4c0", styles: "font-size:12px;position:fixed;top:16px;right:16px;width:320px;background-color:#ffffff;border:1px solid #b0b0b040;border-radius:2px;color:#404040;overflow:hidden;&,button,textarea{font-family:\"SF Mono\",Consolas,Menlo,Monaco,\"Courier New\",Courier,monospace;}" } : { name: "5eq1xc-Pane", styles: "font-size:12px;position:fixed;top:16px;right:16px;width:320px;background-color:#ffffff;border:1px solid #b0b0b040;border-radius:2px;color:#404040;overflow:hidden;&,button,textarea{font-family:\"SF Mono\",Consolas,Menlo,Monaco,\"Courier New\",Courier,monospace;};label:Pane;", toString: _EMOTION_STRINGIFIED_CSS_ERROR__ }; function Pane({ children }) { const rootRef = useRef(null); const headerRef = useRef(null); const offsetRef = useRef([0, 0]); const onUnmountRef = useRef(); function onHeaderMouseDown(e) { let lastPosition = [e.nativeEvent.screenX, e.nativeEvent.screenY]; function onMouseMove(e) { const [lastX, lastY] = lastPosition; const deltaX = e.screenX - lastX; const deltaY = e.screenY - lastY; offsetRef.current[0] += deltaX; offsetRef.current[1] += deltaY; rootRef.current.style.transform = `translate3d(${offsetRef.current[0]}px, ${offsetRef.current[1]}px, 0)`; lastPosition = [e.screenX, e.screenY]; } function cleanup() { window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); } function onMouseUp() { cleanup(); } window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); onUnmountRef.current = cleanup; } useEffect(() => { return () => { if (onUnmountRef.current !== undefined) { onUnmountRef.current(); } }; }, []); return jsxs("div", { css: _ref2, ref: rootRef, children: [jsx("div", { css: _ref, onMouseDown: onHeaderMouseDown, ref: headerRef, children: "manipulative" }), jsx("div", { children: children })] }); } function _EMOTION_STRINGIFIED_CSS_ERROR__$1() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; } const useStore = create(set => ({ callsites: {}, updateCallsite: (location, value) => set(state => Object.assign(Object.assign({}, state), { callsites: Object.assign(Object.assign({}, state.callsites), { [location]: value }) })), removeCallsite: location => set(state => { const newCallsites = Object.assign({}, state.callsites); delete newCallsites[location]; return Object.assign(Object.assign({}, state), { callsites: newCallsites }); }) })); var _ref$1 = process.env.NODE_ENV === "production" ? { name: "1pp55tu", styles: "color:#e45b32;font-size:10px;margin-left:8px" } : { name: "1jx7ql0-Inspector", styles: "color:#e45b32;font-size:10px;margin-left:8px;label:Inspector;", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref2$1 = process.env.NODE_ENV === "production" ? { name: "s5xdrg", styles: "display:flex;align-items:center" } : { name: "jo8tox-Inspector", styles: "display:flex;align-items:center;label:Inspector;", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref3 = process.env.NODE_ENV === "production" ? { name: "157mb91", styles: "color:#b0b0b0;text-decoration:none;:hover{text-decoration:underline;}" } : { name: "157mb91", styles: "color:#b0b0b0;text-decoration:none;:hover{text-decoration:underline;}", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref4 = process.env.NODE_ENV === "production" ? { name: "l07wxm", styles: "font-size:10px;text-align:right;color:#808080;cursor:default" } : { name: "l07wxm", styles: "font-size:10px;text-align:right;color:#808080;cursor:default", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref5 = process.env.NODE_ENV === "production" ? { name: "bmpxd3", styles: "box-sizing:border-box;font-size:12px;height:48px;padding:4px;width:100%" } : { name: "bmpxd3", styles: "box-sizing:border-box;font-size:12px;height:48px;padding:4px;width:100%", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref6 = process.env.NODE_ENV === "production" ? { name: "1ew4t5w", styles: "font-size:12px;margin-bottom:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;cursor:default" } : { name: "1ew4t5w", styles: "font-size:12px;margin-bottom:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;cursor:default", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref7 = process.env.NODE_ENV === "production" ? { name: "5bhc30", styles: "margin-bottom:8px" } : { name: "5bhc30", styles: "margin-bottom:8px", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; var _ref8 = process.env.NODE_ENV === "production" ? { name: "6kp9d7", styles: "padding:12px 12px;button{background-color:#808080;border:0;border-radius:2px;color:#ffffff;cursor:pointer;font-size:10px;letter-spacing:0.2px;padding:6px 10px;text-transform:uppercase;:hover{background-color:#404040;}}" } : { name: "1jkakie-Inspector", styles: "padding:12px 12px;button{background-color:#808080;border:0;border-radius:2px;color:#ffffff;cursor:pointer;font-size:10px;letter-spacing:0.2px;padding:6px 10px;text-transform:uppercase;:hover{background-color:#404040;}};label:Inspector;", toString: _EMOTION_STRINGIFIED_CSS_ERROR__$1 }; function Inspector() { const { callsites, updateCallsite } = useStore(); const [commitState, setCommitState] = useState(); useEffect(() => { // clear commit state on fast refresh return () => setCommitState(undefined); }, []); if (Object.keys(callsites).length === 0) { return null; } return jsx(Pane, { children: jsxs("div", { css: _ref8, children: [Object.keys(callsites).map(location => { const callsite = callsites[location]; const [filePath, position] = location.split(":"); const fileName = filePath.substring(filePath.lastIndexOf("/") + 1); return jsxs("div", { css: _ref7, children: [callsite.codeLine !== undefined ? jsx("div", { onMouseOver: () => { updateCallsite(location, Object.assign(Object.assign({}, callsite), { hover: true })); }, onMouseOut: () => { updateCallsite(location, Object.assign(Object.assign({}, callsite), { hover: false })); }, css: _ref6, children: callsite.codeLine }) : null, jsx("div", { children: jsx("textarea", { value: callsite.value, onChange: e => { updateCallsite(location, Object.assign(Object.assign({}, callsite), { value: e.target.value })); }, css: _ref5 }) }), jsxs("div", { css: _ref4, children: [fileName, " ", jsx("a", { href: `vscode://file${filePath}${callsite.lineNumber !== undefined ? `:${callsite.lineNumber}` : ""}`, css: _ref3, children: position })] })] }, location); }), jsxs("div", { css: _ref2$1, children: [jsx("button", { onClick: () => __awaiter(this, void 0, void 0, function* () { var _a; const updates = []; for (const location in callsites) { const [fileName, position] = location.split(":"); updates.push({ fileName, position: parseInt(position), value: callsites[location].value }); } setCommitState({ type: "committing" }); try { yield fetch(`http://localhost:${(_a = process.env.REACT_APP_MANIPULATIVE_PORT) !== null && _a !== void 0 ? _a : 3199}/commit`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ updates }) }); } catch (e) { setCommitState({ type: "error", error: e.toString() }); } }), children: (commitState === null || commitState === void 0 ? void 0 : commitState.type) === "committing" ? "committing..." : "commit" }), (commitState === null || commitState === void 0 ? void 0 : commitState.type) === "error" ? jsx("div", { css: _ref$1, children: commitState.error }) : null] })] }) }); } let isMounted = false; function mountInspector() { if (isMounted) { return; } const container = document.createElement("div"); document.body.appendChild(container); ReactDOM.render(jsx(Inspector, {}), container); isMounted = true; } function usePlaceholder(location, cssFunction) { const [filename, position, lineNumber, codeLine] = location; const locationKey = `${filename}:${position}`; const callsite = useStore(state => state.callsites[locationKey]); const updateCallsite = useStore(state => state.updateCallsite); const removeCallsite = useStore(state => state.removeCallsite); useEffect(() => { updateCallsite(locationKey, { value: "", hover: false, lineNumber, codeLine }); mountInspector(); return () => { removeCallsite(locationKey); }; }, []); if (callsite === undefined) { return; } return cssFunction(callsite.value, callsite.hover ? cssFunction("box-shadow: inset 0 0 0 9999px rgba(120, 170, 210, 0.7)") : undefined); } function useCssPlaceholder(location) { return /*#__PURE__*/usePlaceholder(location, css, process.env.NODE_ENV === "production" ? "" : ";label:useCssPlaceholder;"); } export { useCssPlaceholder };