mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-22 11:08:10 +00:00
basic css changes
This commit is contained in:
@@ -6,138 +6,153 @@ import { foldGutter, foldKeymap } from "@codemirror/language";
|
||||
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine } from "@codemirror/view";
|
||||
import { markdown } from "@codemirror/lang-markdown";
|
||||
import { css } from "@codemirror/lang-css";
|
||||
import { oneDark } from "@codemirror/theme-one-dark";
|
||||
|
||||
const CodeEditor = forwardRef(({ value = "", onChange = () => {} }, ref) => {
|
||||
const editorRef = useRef(null);
|
||||
const viewRef = useRef(null);
|
||||
const CodeEditor = forwardRef(
|
||||
({ value = "", onChange = () => {}, language, editorTheme, tab, view, style, ...props }, ref) => {
|
||||
const editorRef = useRef(null);
|
||||
const viewRef = useRef(null);
|
||||
|
||||
// --- init editor ---
|
||||
useEffect(() => {
|
||||
if (!editorRef.current) return;
|
||||
console.log(props);
|
||||
|
||||
const updateListener = EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
onChange(update.state.doc.toString());
|
||||
// --- init editor ---
|
||||
useEffect(() => {
|
||||
if (!editorRef.current) return;
|
||||
|
||||
const updateListener = EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
onChange(update.state.doc.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const boldCommand = (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = `**${selected}**`;
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const italicCommand = (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = `*${selected}*`;
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const customKeymap = keymap.of([
|
||||
{ key: "Mod-b", run: boldCommand },
|
||||
{ key: "Mod-i", run: italicCommand },
|
||||
]);
|
||||
|
||||
const languageExtension = () => {
|
||||
switch (language) {
|
||||
case "gfm":
|
||||
return markdown({ codeLanguages: [] }); // GitHub-flavored Markdown
|
||||
case "css":
|
||||
return css();
|
||||
default:
|
||||
return markdown();
|
||||
}
|
||||
};
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: value,
|
||||
extensions: [
|
||||
history(),
|
||||
keymap.of(defaultKeymap),
|
||||
customKeymap,
|
||||
updateListener,
|
||||
languageExtension(),
|
||||
highlightActiveLine(),
|
||||
highlightActiveLineGutter(),
|
||||
keymap.of(foldKeymap),
|
||||
foldGutter(),
|
||||
lineNumbers(),
|
||||
oneDark,
|
||||
],
|
||||
});
|
||||
|
||||
viewRef.current = new EditorView({
|
||||
state,
|
||||
parent: editorRef.current,
|
||||
});
|
||||
|
||||
return () => viewRef.current?.destroy();
|
||||
}, []);
|
||||
|
||||
// --- sync external value ---
|
||||
useEffect(() => {
|
||||
const view = viewRef.current;
|
||||
if (!view) return;
|
||||
|
||||
const current = view.state.doc.toString();
|
||||
if (value !== current) {
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: current.length, insert: value },
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [value]);
|
||||
|
||||
const boldCommand = (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = `**${selected}**`;
|
||||
// --- exposed API ---
|
||||
useImperativeHandle(ref, () => ({
|
||||
getValue: () => viewRef.current.state.doc.toString(),
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
setValue: (text) => {
|
||||
const view = viewRef.current;
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: view.state.doc.length, insert: text },
|
||||
});
|
||||
},
|
||||
|
||||
return true;
|
||||
};
|
||||
injectText: (text) => {
|
||||
const view = viewRef.current;
|
||||
const { from, to } = view.state.selection.main;
|
||||
|
||||
const italicCommand = (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const text = `*${selected}*`;
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
view.focus();
|
||||
},
|
||||
|
||||
return true;
|
||||
};
|
||||
getCursorPosition: () => viewRef.current.state.selection.main.head,
|
||||
|
||||
const customKeymap = keymap.of([
|
||||
{ key: "Mod-b", run: boldCommand },
|
||||
{ key: "Mod-i", run: italicCommand },
|
||||
]);
|
||||
setCursorPosition: (pos) => {
|
||||
viewRef.current.dispatch({ selection: { anchor: pos } });
|
||||
viewRef.current.focus();
|
||||
},
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: value,
|
||||
extensions: [
|
||||
history(),
|
||||
keymap.of(defaultKeymap),
|
||||
customKeymap,
|
||||
updateListener,
|
||||
markdown(),
|
||||
css(),
|
||||
highlightActiveLine(),
|
||||
highlightActiveLineGutter(),
|
||||
keymap.of(foldKeymap),
|
||||
foldGutter(),
|
||||
lineNumbers(),
|
||||
|
||||
],
|
||||
});
|
||||
undo: () => undo(viewRef.current),
|
||||
redo: () => redo(viewRef.current),
|
||||
|
||||
viewRef.current = new EditorView({
|
||||
state,
|
||||
parent: editorRef.current,
|
||||
});
|
||||
historySize: () => {
|
||||
const view = viewRef.current;
|
||||
if (!view) return { done: 0, undone: 0 };
|
||||
|
||||
return () => viewRef.current?.destroy();
|
||||
}, []);
|
||||
const h = view.state.field(historyField, false);
|
||||
if (!h) return { done: 0, undone: 0 };
|
||||
|
||||
// --- sync external value ---
|
||||
useEffect(() => {
|
||||
const view = viewRef.current;
|
||||
if (!view) return;
|
||||
return { done: h.done.length, undone: h.undone.length };
|
||||
},
|
||||
|
||||
const current = view.state.doc.toString();
|
||||
if (value !== current) {
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: current.length, insert: value },
|
||||
});
|
||||
}
|
||||
}, [value]);
|
||||
focus: () => viewRef.current.focus(),
|
||||
}));
|
||||
|
||||
// --- exposed API ---
|
||||
useImperativeHandle(ref, () => ({
|
||||
getValue: () => viewRef.current.state.doc.toString(),
|
||||
return <div className="codeEditor" ref={editorRef} style={style} />;
|
||||
},
|
||||
);
|
||||
|
||||
setValue: (text) => {
|
||||
const view = viewRef.current;
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: view.state.doc.length, insert: text },
|
||||
});
|
||||
},
|
||||
|
||||
injectText: (text) => {
|
||||
const view = viewRef.current;
|
||||
const { from, to } = view.state.selection.main;
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: text },
|
||||
selection: { anchor: from + text.length },
|
||||
});
|
||||
|
||||
view.focus();
|
||||
},
|
||||
|
||||
getCursorPosition: () => viewRef.current.state.selection.main.head,
|
||||
|
||||
setCursorPosition: (pos) => {
|
||||
viewRef.current.dispatch({ selection: { anchor: pos } });
|
||||
viewRef.current.focus();
|
||||
},
|
||||
|
||||
undo: () => undo(viewRef.current),
|
||||
redo: () => redo(viewRef.current),
|
||||
|
||||
historySize: () => {
|
||||
const view = viewRef.current;
|
||||
if (!view) return { done: 0, undone: 0 };
|
||||
|
||||
const h = view.state.field(historyField, false);
|
||||
if (!h) return { done: 0, undone: 0 };
|
||||
|
||||
return { done: h.done.length, undone: h.undone.length };
|
||||
},
|
||||
|
||||
focus: () => viewRef.current.focus(),
|
||||
}));
|
||||
|
||||
return <div ref={editorRef} style={{ height: "100%" }} />;
|
||||
});
|
||||
|
||||
export default CodeEditor;
|
||||
export default CodeEditor;
|
||||
|
||||
Reference in New Issue
Block a user