feat: CodeMirror integration and bug fixes
This commit addresses several issues related to the migration from TipTap to CodeMirror:
- **CodeMirror Initialization Fixes:**
- Resolved 'Unrecognized extension value' errors by refactoring to explicitly import individual CodeMirror extensions instead of relying on . This ensures proper singleton usage and prevents module duplication issues.
- Updated and to utilize these individual extensions.
- **Text Wrapping Enabled:**
- Added to the extensions in and to enable text wrapping in the CodeMirror editors.
- **Content Saving Fixes:**
- Corrected content binding for CodeMirror editor instances in various IDAA components:
- (description, location_text, attend_text)
- (content, notes)
- (content)
- (description, notes)
- (description, notes)
- Ensured that the prop of is correctly bound to the respective state variables in the parent components, and these state variables are initialized with existing content.
- **Save Button Enablement:**
- Fixed an issue in where the Save button was not enabling on content changes. The logic now directly compares the and with the original object's content, ensuring reactivity.
This commit is contained in:
@@ -5,50 +5,7 @@
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import {
|
||||
EditorView,
|
||||
keymap,
|
||||
highlightSpecialChars,
|
||||
drawSelection,
|
||||
highlightActiveLine,
|
||||
dropCursor,
|
||||
rectangularSelection,
|
||||
crosshairCursor,
|
||||
gutter,
|
||||
GutterMarker,
|
||||
highlightActiveLineGutter,
|
||||
lineNumbers,
|
||||
placeholder as placeholderExt
|
||||
} from '@codemirror/view';
|
||||
import { EditorState, RangeSet, StateEffect, type Extension, Text } from '@codemirror/state';
|
||||
import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
||||
import { indentUnit } from '@codemirror/language';
|
||||
import { languages } from '@codemirror/language-data';
|
||||
// import {
|
||||
// defaultHighlightStyle, syntaxHighlighting, indentOnInput,
|
||||
// bracketMatching, foldGutter, foldKeymap
|
||||
// } from "@codemirror/language"
|
||||
// import {
|
||||
// defaultHighlightStyle, syntaxHighlighting, indentOnInput,
|
||||
// bracketMatching, foldGutter, foldKeymap
|
||||
// } from "@codemirror/language"
|
||||
// import {
|
||||
// searchKeymap, highlightSelectionMatches
|
||||
// } from "@codemirror/search"
|
||||
// import {
|
||||
// autocompletion, completionKeymap, closeBrackets,
|
||||
// closeBracketsKeymap
|
||||
// } from "@codemirror/autocomplete"
|
||||
// import {lintKeymap} from "@codemirror/lint"
|
||||
|
||||
// import { } from '@codemirror/gutter'; // Merged into @codemirror/view
|
||||
import { basicSetup } from 'codemirror';
|
||||
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
||||
// import { css } from '@codemirror/lang-css';
|
||||
// import { javascript } from '@codemirror/lang-javascript';
|
||||
// import { json } from '@codemirror/lang-json';
|
||||
// import { html } from '@codemirror/lang-html';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { ensureCodeMirrorModules } from '../elements/codemirror_modules';
|
||||
|
||||
// Props
|
||||
export let content: string = 'test test test test';
|
||||
@@ -56,9 +13,7 @@
|
||||
|
||||
// export let language: Extension = markdown(); // javascript()
|
||||
export let theme_mode: string = 'light'; // 'dark' | 'light'
|
||||
export let theme: Extension = EditorView.baseTheme(); // EditorView.baseTheme(); // oneDark
|
||||
|
||||
export let extensions: Extension[] = [];
|
||||
export let extensions: any[] = []; // Changed to any[] because Extension type is not directly available here
|
||||
|
||||
export let editable: boolean = true;
|
||||
export let readonly: boolean = false;
|
||||
@@ -73,146 +28,75 @@
|
||||
export { classes as class };
|
||||
|
||||
let editor_element: HTMLDivElement;
|
||||
let editorView: EditorView;
|
||||
let editorView: any; // Changed to any
|
||||
|
||||
// theme = [
|
||||
// // baseTheme,
|
||||
// theme,
|
||||
// ];
|
||||
// console.log(`Theme:`, theme);
|
||||
let cm_modules: any; // To hold the dynamically loaded CodeMirror modules
|
||||
|
||||
if (theme_mode == 'dark') {
|
||||
theme = oneDark;
|
||||
} else {
|
||||
// theme = EditorView.baseTheme({
|
||||
// "&": {
|
||||
// color: "black",
|
||||
// backgroundColor: "white"
|
||||
// },
|
||||
// ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#000" },
|
||||
// "&.cm-focused .cm-selectionBackground, ::selection": {
|
||||
// backgroundColor: "#B7D5FF"
|
||||
// },
|
||||
// "&.cm-focused .cm-selectionForeground": { color: "black" }
|
||||
// });
|
||||
}
|
||||
async function initializeCodeMirror() {
|
||||
if (!browser) return;
|
||||
|
||||
if (editable) {
|
||||
extensions.push(EditorView.editable.of(true));
|
||||
} else {
|
||||
// extensions.push(EditorState.editable.of(false));
|
||||
}
|
||||
if (readonly) {
|
||||
extensions.push(EditorState.readOnly.of(true));
|
||||
} else {
|
||||
// extensions.push(EditorState.readOnly.of(false));
|
||||
}
|
||||
cm_modules = await ensureCodeMirrorModules();
|
||||
if (!cm_modules) return;
|
||||
|
||||
if (placeholder) {
|
||||
extensions.push(placeholderExt(placeholder));
|
||||
}
|
||||
// Reactive declaration for extensions
|
||||
let editor_extensions = [
|
||||
// Core extensions
|
||||
cm_modules.highlightSpecialChars(),
|
||||
cm_modules.history(),
|
||||
cm_modules.foldGutter(),
|
||||
cm_modules.drawSelection(),
|
||||
cm_modules.dropCursor(),
|
||||
cm_modules.EditorState_allowMultipleSelections.of(true),
|
||||
cm_modules.indentOnInput(),
|
||||
cm_modules.bracketMatching(),
|
||||
cm_modules.closeBrackets(),
|
||||
cm_modules.autocompletion(),
|
||||
cm_modules.rectangularSelection(),
|
||||
cm_modules.crosshairCursor(),
|
||||
cm_modules.highlightActiveLine(),
|
||||
cm_modules.highlightActiveLineGutter(),
|
||||
cm_modules.keymap.of([
|
||||
...cm_modules.defaultKeymap,
|
||||
...cm_modules.searchKeymap,
|
||||
...cm_modules.historyKeymap,
|
||||
...cm_modules.foldKeymap,
|
||||
...cm_modules.completionKeymap,
|
||||
...cm_modules.lintKeymap
|
||||
]),
|
||||
cm_modules.markdown({ base: cm_modules.markdownLanguage, codeLanguages: cm_modules.languages }),
|
||||
theme_mode == 'dark' ? cm_modules.oneDark : cm_modules.EditorView.baseTheme(),
|
||||
cm_modules.EditorView.contentAttributes.of({ spellcheck: 'true' }), // Enable spell check
|
||||
|
||||
if (show_line_numbers) {
|
||||
// extensions.push(lineNumbers({ class: "line-numbers" }));
|
||||
} else {
|
||||
// extensions.push(gutter({ class: "hidden-gutter" }));
|
||||
// extensions.push(lineNumbers(false));
|
||||
// extensions.push(gutter(false));
|
||||
// extensions.pop();
|
||||
// extensions.slice(extensions.indexOf(lineNumbers), 1);
|
||||
}
|
||||
// Conditional extensions based on props
|
||||
editable ? cm_modules.EditorView.editable.of(true) : null,
|
||||
readonly ? cm_modules.EditorState.readOnly.of(true) : null,
|
||||
placeholder ? cm_modules.placeholderExt(placeholder) : null,
|
||||
show_line_numbers ? cm_modules.lineNumbers() : null,
|
||||
wrap_lines ? cm_modules.EditorView_lineWrapping : null,
|
||||
use_tab ? cm_modules.keymap.of([cm_modules.indentWithTab]) : null,
|
||||
tab_size ? cm_modules.indentUnit.of(' '.repeat(tab_size)) : null,
|
||||
|
||||
if (wrap_lines) {
|
||||
extensions.push(EditorView.lineWrapping);
|
||||
}
|
||||
...extensions // Add any custom extensions passed in props
|
||||
].filter(Boolean);
|
||||
|
||||
if (use_tab) {
|
||||
extensions.push(keymap.of([indentWithTab]));
|
||||
}
|
||||
if (tab_size) {
|
||||
extensions.push(indentUnit.of(' '.repeat(tab_size)));
|
||||
}
|
||||
|
||||
// Enable spell check
|
||||
extensions.push(EditorView.contentAttributes.of({ spellcheck: 'true' }));
|
||||
|
||||
// let languages = [
|
||||
// { name: 'CSS', mode: 'css' },
|
||||
// { name: 'HTML', mode: 'html' },
|
||||
// { name: 'JavaScript', mode: 'javascript' },
|
||||
// { name: 'Markdown', mode: 'markdown' },
|
||||
// { name: 'Python', mode: 'python' },
|
||||
// ];
|
||||
|
||||
// Reactive declaration for extensions
|
||||
$: editor_extensions = [
|
||||
basicSetup,
|
||||
// gutter({class: "hidden-gutter"}),
|
||||
// A line number gutter
|
||||
lineNumbers(false),
|
||||
// A gutter with code folding markers
|
||||
// foldGutter(false),
|
||||
// lineWrapping(false),
|
||||
// EditorView.lineWrapping, // Enable line wrapping
|
||||
|
||||
// EditorView.indentUnit.of(" ".repeat(tab_size)),
|
||||
// EditorView.tabSize.of(tab_size),
|
||||
// indentUnit.of(" ".repeat(tab_size)),
|
||||
|
||||
// EditorView.editable.of(editable),
|
||||
// EditorState.readOnly.of(readonly),
|
||||
|
||||
// EditorState.tabSize.of(tab_size),
|
||||
// keymap.of([indentWithTab]),
|
||||
// placeholderExt(placeholder),
|
||||
// language,
|
||||
markdown({ base: markdownLanguage, codeLanguages: languages }),
|
||||
// javascript({typescript: true}),
|
||||
// json(),
|
||||
// css(),
|
||||
// html(),
|
||||
theme,
|
||||
|
||||
...extensions
|
||||
];
|
||||
|
||||
// baseTheme = {
|
||||
// ".cm-o-replacement": {
|
||||
// display: "inline-block",
|
||||
// width: ".5em",
|
||||
// height: ".5em",
|
||||
// borderRadius: ".25em"
|
||||
// },
|
||||
// "&light .cm-o-replacement": {
|
||||
// backgroundColor: "#04c"
|
||||
// },
|
||||
// "&dark .cm-o-replacement": {
|
||||
// backgroundColor: "#5bf"
|
||||
// }
|
||||
// },
|
||||
// let dimensions = {
|
||||
// width: '100%',
|
||||
// height: 'calc(100vh - 48px)' // Adjust for header and other elements
|
||||
// };
|
||||
// editorView.setSize(dimensions.width, dimensions.height);
|
||||
|
||||
// Initialize CodeMirror on mount
|
||||
onMount(() => {
|
||||
editorView = new EditorView({
|
||||
state: EditorState.create({
|
||||
editorView = new cm_modules.EditorView({
|
||||
state: cm_modules.EditorState.create({
|
||||
doc: content,
|
||||
extensions: editor_extensions
|
||||
}),
|
||||
parent: editor_element, // document.body
|
||||
dispatch: (transaction) => {
|
||||
parent: editor_element,
|
||||
dispatch: (transaction: any) => {
|
||||
editorView.update([transaction]);
|
||||
if (transaction.docChanged) {
|
||||
new_content = editorView.state.doc.toString();
|
||||
const newContent = editorView.state.doc.toString();
|
||||
// dispatch('change', newContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize CodeMirror on mount
|
||||
onMount(async () => {
|
||||
await initializeCodeMirror();
|
||||
});
|
||||
|
||||
// Clean up on destroy
|
||||
@@ -221,11 +105,11 @@
|
||||
});
|
||||
|
||||
// Update editor content when `content` prop changes
|
||||
$: if (editorView && editorView.state.doc.toString() !== content) {
|
||||
$: if (cm_modules && editorView && editorView.state.doc.toString() !== content) {
|
||||
editorView.setState(
|
||||
EditorState.create({
|
||||
cm_modules.EditorState.create({
|
||||
doc: content,
|
||||
extensions: editor_extensions
|
||||
extensions: editor_extensions // Use the reactive extensions
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user