Update dependencies & directly include editor

This commit is contained in:
Jade Ellis
2024-06-16 16:05:52 +01:00
parent f23e0417ed
commit 858914a73e
6 changed files with 838 additions and 647 deletions
+158 -23
View File
@@ -1,9 +1,4 @@
<script lang="ts" context="module">
export enum LanguageConfig {
None,
JavaScript,
}
type Attrs = {
[name: string]: string;
};
@@ -12,34 +7,156 @@
<script lang="ts">
// look at https://github.com/sveltejs/learn.svelte.dev/blob/main/src/routes/tutorial/%5Bslug%5D/Editor.svelte
import CodeMirror from "svelte-codemirror-editor";
import { javascript } from "@codemirror/lang-javascript";
// import { javascript } from "@codemirror/lang-javascript";
import { onDestroy, onMount, createEventDispatcher } from "svelte";
import { theme } from "$lib/theme";
import { githubLight, githubDark } from "$lib/themes/github";
import type { Extension } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import {
EditorState,
StateEffect,
type Extension,
} from "@codemirror/state";
import { type LanguageSupport } from "@codemirror/language";
import { get_base_extensions } from "./editorExtensions";
export let value = "";
export let contentAttributes: AttrSource | null = null;
export let lang: LanguageSupport | null = null;
export let useTab = true;
export let tabSize = 2;
export let lineWrapping = false;
export let editable = true;
export let readonly = false;
export let lang: LanguageConfig = LanguageConfig.None;
export let placeholder: string | HTMLElement | null | undefined = undefined;
const is_browser = typeof window !== "undefined";
let element: HTMLDivElement;
let view: EditorView;
$: view && update(value);
$: view && state_extensions && reconfigure();
$: on_change = handle_change;
let update_from_prop = false;
let update_from_state = false;
let first_config = true;
let first_update = true;
let langPlugin = null;
switch (lang) {
case LanguageConfig.None:
langPlugin = null;
break;
case LanguageConfig.JavaScript:
langPlugin = javascript();
break;
let extensions: Extension[] = [];
default:
break;
}
let extensions: Extension[] = [
$: state_extensions = [
...get_base_extensions(
useTab,
tabSize,
lineWrapping,
placeholder,
editable,
readonly,
lang,
),
$theme == "dark" ? githubDark : githubLight,
...extensions,
];
if (langPlugin !== null) extensions.push(langPlugin);
if (contentAttributes !== null) extensions.push(EditorView.contentAttributes.of(contentAttributes));
if (contentAttributes !== null)
extensions.push(EditorView.contentAttributes.of(contentAttributes));
onMount(() => {
view = create_editor_view();
dispatch("ready", view);
});
onDestroy(() => view?.destroy());
const dispatch = createEventDispatcher<{
change: string;
ready: EditorView;
reconfigure: EditorView;
}>();
function create_editor_view(): EditorView {
return new EditorView({
parent: element,
state: create_editor_state(value),
dispatch(transaction) {
view.update([transaction]);
if (!update_from_prop && transaction.docChanged) {
on_change();
}
},
});
}
function reconfigure(): void {
if (first_config) {
first_config = false;
return;
}
view.dispatch({
effects: StateEffect.reconfigure.of(state_extensions),
});
dispatch("reconfigure", view);
}
function update(value: string | null | undefined): void {
if (first_update) {
first_update = false;
return;
}
if (update_from_state) {
update_from_state = false;
return;
}
update_from_prop = true;
if (value === undefined) {
return;
}
const currentValue = view ? view.state.doc.toString() : "";
if (view && value !== currentValue) {
view.dispatch({
changes: {
from: 0,
to: currentValue.length,
insert: value || "",
},
});
}
update_from_prop = false;
}
function handle_change(): void {
const new_value = view.state.doc.toString();
if (new_value === value) return;
update_from_state = true;
value = new_value;
dispatch("change", value);
}
function create_editor_state(
value: string | null | undefined,
): EditorState {
return EditorState.create({
doc: value ?? undefined,
extensions: state_extensions,
});
}
// $: console.log(value)
@@ -56,15 +173,28 @@
<slot name="header" />
</div>
{/if}
<CodeMirror
{#if is_browser}
<div class="codemirror-wrapper editor" bind:this={element} />
{:else}
<div class="scm-waiting editor">
<div class="scm-waiting__loading scm-loading">
<div class="scm-loading__spinner" />
<p class="scm-loading__text">Loading editor...</p>
</div>
<pre class="scm-pre cm-editor">{value}</pre>
</div>
{/if}
<!-- <CodeMirror
{value}
class="editor"
theme={$theme == "dark" ? githubDark : githubLight}
{extensions}
{readonly}
on:change
/>
/> -->
</div>
<!-- <CodeMirror basic={true} bind:value lang={javascript({})} class="editor" /> -->
<style>
@@ -74,6 +204,11 @@
z-index: 1;
background-color: var(--surface-secondary-color);
}
.codemirror-wrapper :global(.cm-focused) {
outline: none;
}
:global(.editor-wrapper .cm-scroller, .editor-wrapper .cm-editor) {
min-height: 200px;
border-bottom-left-radius: var(--border-radius);
@@ -0,0 +1,30 @@
import { type LanguageSupport, indentUnit } from "@codemirror/language";
import { type Extension, EditorState } from "@codemirror/state";
import { EditorView, keymap } from "@codemirror/view";
import { indentWithTab } from "@codemirror/commands";
import { basicSetup } from "codemirror";
export function get_base_extensions(
useTab: boolean,
tabSize: number,
lineWrapping: boolean,
placeholder: string | HTMLElement | null | undefined,
editable: boolean,
readonly: boolean,
lang: LanguageSupport | null | undefined
): Extension[] {
const extensions: Extension[] = [
indentUnit.of(" ".repeat(tabSize)),
EditorView.editable.of(editable),
EditorState.readOnly.of(readonly),
basicSetup
];
if (useTab) extensions.push(keymap.of([indentWithTab]));
// if (placeholder) extensions.push(placeholderExt(placeholder));
if (lang) extensions.push(lang);
if (lineWrapping) extensions.push(EditorView.lineWrapping);
return extensions;
}
@@ -1,5 +1,6 @@
<script lang="ts">
import Editor, { LanguageConfig } from "$lib/Editor.svelte";
import Editor from "$lib/Editor.svelte";
import { javascript } from "@codemirror/lang-javascript";
import SvelteSeo from "svelte-seo";
import { bookmarkify, parseMeta } from "./bookmarklets";
import type { Config } from "./config";
@@ -39,7 +40,7 @@
<Editor
{value}
on:change={(e) => (value = e.detail)}
lang={LanguageConfig.JavaScript}
lang={javascript()}
{contentAttributes}
>
<div slot="header" class="code-header">Input</div>
@@ -1,6 +1,6 @@
import MagicString from "magic-string";
// import MagicString from "magic-string";
import { Parser } from "acorn";
import { type MinifyOptions, type MinifyOutput } from "terser";