uiwjs / uiwjs/react-codemirror
Duplicate mergeView elements
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.3k
- Forks
- 161
- PR merge metrics
- No merged PRs in 30d
Description
I'm trying to adjust the height of a CodeMirrorMerge.
In reading about how to do this, it seems that the recommended practice is to modify the .cm-mergeView CSS class.
I did this and noticed that there are multiple <div> elements that seem to be duplicate instances.
In the below, the highlighted portion represents one of the two instances, and it's empty with a height of ~30px.
The second instance shows what is expected with the text that needs diffing.
One problem around this is that adjusting the height on the .cm-mergeView class adjusts the heights on both elements, but the real problem seems to be that there are duplicates.
I can't think of anywhere in my code that is creating two codeMerges, but I could very well be doing something wrong.
Any help toward figuring out this issue would be most appreciated.
import { useContext, useMemo, useState } from "react";
import { ActionType } from "../../../types"; // enum
import { Button, Spinner } from "react-bootstrap";
import { EditorState } from "@codemirror/state";
import { EditorView } from "codemirror";
import { markdown } from "@codemirror/lang-markdown";
import { materialDarkInit } from "@uiw/codemirror-theme-material";
import { restoreScene } from "../../../actions";
import { solarizedLightInit } from "@uiw/codemirror-theme-solarized";
import { ThemeContext } from "../../../contexts/ThemeProvider";
import { useAppDispatch, useAppSelector } from "../../../hooks/reduxHooks";
import { vim } from "@replit/codemirror-vim";
import CodeMirrorMerge from "react-codemirror-merge";
import config from "../../../config/config.json";
export default function MergeEditor() {
const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;
const { app } = useAppSelector((state) => state);
const dispatch = useAppDispatch();
const { isDark } = useContext(ThemeContext);
const [changedText, setChangedText] = useState("");
const [spinning, setSpinning] = useState(false);
const { abandonedScene, original, modified } = useMemo(() => {
let modified = "";
const abandonedScene = app.scenes.find(
(item) => item.id === app.abandonedSceneId
);
const original = abandonedScene?.text;
const draftInStorage = localStorage.getItem(config.DRAFT_SCENE_KEY);
if (draftInStorage) {
const unsavedScene = JSON.parse(draftInStorage);
if (abandonedScene?.id === unsavedScene?.id) {
modified = unsavedScene.text.trim();
}
}
return { abandonedScene, original, modified };
}, [app.abandonedSceneId, app.scenes]);
// const height = useMemo(() => {
// return `calc(100vh - ${sizes.totalHeightOffset + 32}px)`;
// }, [sizes.totalHeightOffset]);
function handleChange(str: string) {
setChangedText(str);
}
function handleClose() {
dispatch({
type: ActionType.SET_MERGE_EDITOR,
payload: { isDiffingAbandonedScene: false },
});
}
function handleAbandon() {
localStorage.removeItem(config.DRAFT_SCENE_KEY);
handleClose();
}
async function handleRestore() {
try {
setSpinning(true);
if (!abandonedScene) {
throw new Error("No abandoned scene!");
}
await dispatch(
restoreScene({ ...abandonedScene, text: changedText })
);
setSpinning(false);
localStorage.removeItem(config.DRAFT_SCENE_KEY);
handleClose();
} catch (error) {
setSpinning(false);
}
}
const { defaultThemeOptions, theme } = useMemo(() => {
const defaultThemeOptions = EditorView.theme(
{
"&": {
background: isDark
? "#2e3235 !important"
: "#2e3235 !important",
backgroundColor: isDark
? "#2e3235 !important"
: "#fdf6e3 !important",
foreground: isDark
? "#bdbdbd !important"
: "#657b83 !important",
caret: isDark ? "#a0a4ae !important" : "#586e75 !important",
selection: isDark
? "#d7d4f0 !important"
: "#dfd9c8 !important",
selectionMatch: isDark
? "#d7d4f0 !important"
: "#dfd9c8 !important",
gutterBackground: isDark
? "#2e3235 !important"
: "#00000010 !important",
gutterActiveBackground: isDark
? "#4f5b66 !important"
: "#00000010 !important",
gutterActiveForeground: isDark
? "#000 !important"
: "#657b83 !important",
gutterForeground: isDark
? // ? "#999 !important"
"#ff69b4 !important"
: "#657b83 !important",
lineHighlight: isDark
? "#545b61 !important"
: "#dfd9c8 !important",
},
},
{
dark: isDark,
}
);
const theme = isDark
? materialDarkInit({ theme: "dark" })
: solarizedLightInit({ theme: "light" });
return { defaultThemeOptions, theme };
}, [isDark]);
return (
<div className="container d-flex flex-column align-items-center w-100">
<CodeMirrorMerge
className="w-100"
gutter={false}
highlightChanges
orientation="a-b"
revertControls="b-to-a"
>
<Original
extensions={[
vim({ status: false }),
defaultThemeOptions,
theme,
markdown(),
EditorView.lineWrapping,
EditorView.contentAttributes.of({ spellcheck: "true" }),
]}
value={original}
onChange={(str) => handleChange(str)}
/>
<Modified
value={modified}
extensions={[
vim({ status: false }),
defaultThemeOptions,
theme,
markdown(),
EditorView.lineWrapping,
EditorView.editable.of(false),
EditorState.readOnly.of(true),
]}
/>
</CodeMirrorMerge>
<div className="d-flex justify-content-between w-100">
<small>Current Scene</small>
<small>Unsaved Changes (read only)</small>
</div>
{changedText !== modified && (
<div className="d-flex justify-content-center mt-3 w-100">
You can merge the unsaved changes by clicking the little
arrow
</div>
)}
<div className="d-flex align-items-center justify-content-between my-5 w-100">
<Button
className="d-flex align-items-center justify-content-center"
onClick={() => handleAbandon()}
style={{ width: 200 }}
variant="danger"
>
<i className="bi bi-trash" />
<span className="ms-2">Abandon Changes</span>
</Button>
<div className="d-flex align-items-center">
<Button
className="d-flex align-items-center justify-content-center ms-3"
onClick={() => handleRestore()}
disabled={changedText === original}
style={{ width: 200 }}
>
{spinning ? (
<Spinner size="sm" />
) : (
<i className="bi bi-cloud-arrow-up" />
)}
<span className="ms-2">Save Changes</span>
</Button>
</div>
</div>
</div>
);
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the report with the provided MergeEditor component and its CodeMirrorMerge, Original, and Modified usage. Inspect the rendered .cm-mergeView elements to determine whether the duplicate nodes come from the component or the integration. Done means identifying the cause and confirming that the merge view renders only the intended elements without breaking diffing or resizing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100