288 lines
8.2 KiB
Svelte
288 lines
8.2 KiB
Svelte
<script lang="ts">
|
|
// This will be the wrapper for the CodeMirror editor. It should hide most of the configuration requirements.
|
|
// WARNING: This has not been fully updated to Svelte version 5. It is a work in progress.
|
|
// *** Import Svelte version 5 specific
|
|
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";
|
|
|
|
// Props
|
|
export let content: string = 'test test test test';
|
|
export let new_content: string = '';
|
|
|
|
// 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 editable: boolean = true;
|
|
export let readonly: boolean = false;
|
|
|
|
export let placeholder: string = 'Start typing...';
|
|
|
|
export let show_line_numbers: boolean = false;
|
|
export let wrap_lines: boolean = true;
|
|
export let use_tab: boolean = true;
|
|
export let tab_size: number = 4;
|
|
let classes = "";
|
|
export { classes as class };
|
|
|
|
let editor_element: HTMLDivElement;
|
|
let editorView: EditorView;
|
|
|
|
// theme = [
|
|
// // baseTheme,
|
|
// theme,
|
|
// ];
|
|
// console.log(`Theme:`, theme);
|
|
|
|
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" }
|
|
// });
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
if (placeholder) { extensions.push(placeholderExt(placeholder)); }
|
|
|
|
if (show_line_numbers) {
|
|
// extensions.push(lineNumbers({ class: "line-numbers" }));
|
|
} else {
|
|
// extensions.push(lineNumbers(false));
|
|
// extensions.push(gutter(false));
|
|
// extensions.pop();
|
|
// extensions.slice(extensions.indexOf(lineNumbers), 1);
|
|
|
|
}
|
|
|
|
if (wrap_lines) { extensions.push(EditorView.lineWrapping); }
|
|
|
|
if (use_tab) { extensions.push(keymap.of([indentWithTab])); }
|
|
if (tab_size) { extensions.push(indentUnit.of(" ".repeat(tab_size))); }
|
|
|
|
|
|
|
|
// 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({
|
|
doc: content,
|
|
extensions: editor_extensions,
|
|
}),
|
|
parent: editor_element, // document.body
|
|
dispatch: (transaction) => {
|
|
editorView.update([transaction]);
|
|
if (transaction.docChanged) {
|
|
new_content = editorView.state.doc.toString();
|
|
const newContent = editorView.state.doc.toString();
|
|
// dispatch('change', newContent);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Clean up on destroy
|
|
onDestroy(() => {
|
|
editorView?.destroy();
|
|
});
|
|
|
|
// Update editor content when `content` prop changes
|
|
$: if (editorView && editorView.state.doc.toString() !== content) {
|
|
editorView.setState(
|
|
EditorState.create({
|
|
doc: content,
|
|
extensions: editor_extensions
|
|
})
|
|
);
|
|
};
|
|
</script>
|
|
|
|
{#if browser}
|
|
<!-- flex flex-col flex-wrap items-center justify-center -->
|
|
<div bind:this={editor_element} class="codemirror-wrapper h-100 max-h-full w-100 max-w-6xl {classes}"></div>
|
|
{:else}
|
|
<div class="scm-waiting {classes}">
|
|
<div class="scm-waiting__loading scm-loading">
|
|
<p class="scm-loading__text">Loading editor...</p>
|
|
</div>
|
|
|
|
<pre class="scm-pre cm-editor">{content}</pre>
|
|
</div>
|
|
{/if}
|
|
|
|
<style>
|
|
/* .codemirror-wrapper :global(.cm-focused) {
|
|
outline: none;
|
|
} */
|
|
|
|
.codemirror-wrapper {
|
|
flex-grow: 1;
|
|
/* flex-shrink: 1; */
|
|
/* flex-basis: 100%; */
|
|
|
|
/* font-size: 1rem; */
|
|
width: 100%;
|
|
max-width: 100%;
|
|
height: 100%;
|
|
max-height: 100%;
|
|
/* overflow: auto; */
|
|
/* background-color: var(--cm-background); */
|
|
|
|
/* text-wrap: normal; */
|
|
/* text-wrap: balance; */
|
|
/* text-wrap: wrap; */
|
|
/* text-wrap: break-word; */
|
|
}
|
|
.codemirror-wrapper :global(.cm-editor) {
|
|
/* font-size: .8rem; */
|
|
/* text-wrap: normal; */
|
|
/* text-wrap: balance; */
|
|
/* text-wrap: wrap; */
|
|
/* text-wrap: break-word; */
|
|
|
|
/* max-width: 100%; */
|
|
/* max-height: 100%; */
|
|
|
|
/* overflow: auto; */
|
|
|
|
/* width: 100%; */
|
|
/* height: 100%; */
|
|
|
|
/* background-color: var(--cm-background); */
|
|
/* color: var(--cm-text); */
|
|
}
|
|
|
|
/* .codemirror-wrapper :global(.cm-gutters) {
|
|
background-color: var(--cm-gutter-background);
|
|
color: var(--cm-gutter-text);
|
|
}
|
|
.codemirror-wrapper :global(.cm-gutter) {
|
|
background-color: var(--cm-gutter-background);
|
|
color: var(--cm-gutter-text);
|
|
}
|
|
.codemirror-wrapper :global(.cm-gutterElement) {
|
|
background-color: var(--cm-gutter-background);
|
|
color: var(--cm-gutter-text);
|
|
} */
|
|
|
|
</style> |