Add QOL addons to CodeMirror editor
This commit is contained in:
parent
6d8507d95e
commit
d6ca48b46a
|
@ -0,0 +1,146 @@
|
||||||
|
<script context="module">
|
||||||
|
export const EditorModes = {
|
||||||
|
JS: {
|
||||||
|
name: "javascript",
|
||||||
|
json: false,
|
||||||
|
},
|
||||||
|
JSON: {
|
||||||
|
name: "javascript",
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
SQL: {
|
||||||
|
name: "sql",
|
||||||
|
},
|
||||||
|
Handlebars: {
|
||||||
|
name: "handlebars",
|
||||||
|
base: "text/html",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CodeMirror from "components/integration/codemirror"
|
||||||
|
import { themeStore } from "builderStore"
|
||||||
|
import { createEventDispatcher, onMount } from "svelte"
|
||||||
|
|
||||||
|
export let mode = EditorModes.JS
|
||||||
|
export let value = ""
|
||||||
|
export let height = 300
|
||||||
|
export let readonly = false
|
||||||
|
export let hints = []
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let textarea
|
||||||
|
let editor
|
||||||
|
|
||||||
|
// Keep editor up to date with value
|
||||||
|
$: editor?.setValue(value || "")
|
||||||
|
|
||||||
|
// Creates an instance of a code mirror editor
|
||||||
|
async function createEditor(mode, value) {
|
||||||
|
if (!CodeMirror || !textarea || editor) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure CM options
|
||||||
|
const lightTheme = $themeStore.theme.includes("light")
|
||||||
|
const options = {
|
||||||
|
mode,
|
||||||
|
value: value || "",
|
||||||
|
readOnly: readonly,
|
||||||
|
theme: lightTheme ? "default" : "tomorrow-night-eighties",
|
||||||
|
|
||||||
|
// Style
|
||||||
|
lineNumbers: true,
|
||||||
|
lineWrapping: true,
|
||||||
|
indentWithTabs: true,
|
||||||
|
indentUnit: 2,
|
||||||
|
tabSize: 2,
|
||||||
|
|
||||||
|
// QOL addons
|
||||||
|
extraKeys: { "Ctrl-Space": "autocomplete" },
|
||||||
|
styleActiveLine: { nonEmpty: true },
|
||||||
|
autoCloseBrackets: true,
|
||||||
|
matchBrackets: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register hints plugin if desired
|
||||||
|
if (hints?.length) {
|
||||||
|
CodeMirror.registerHelper("hint", "dictionaryHint", function (editor) {
|
||||||
|
const cursor = editor.getCursor()
|
||||||
|
return {
|
||||||
|
list: hints,
|
||||||
|
from: CodeMirror.Pos(cursor.line, cursor.ch),
|
||||||
|
to: CodeMirror.Pos(cursor.line, cursor.ch),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
CodeMirror.commands.autocomplete = function (cm) {
|
||||||
|
CodeMirror.showHint(cm, CodeMirror.hint.dictionaryHint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct CM instance
|
||||||
|
editor = CodeMirror.fromTextArea(textarea, options)
|
||||||
|
|
||||||
|
// Use a blur handler to update the value
|
||||||
|
editor.on("blur", instance => {
|
||||||
|
dispatch("change", instance.getValue())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export a function to expose caret position
|
||||||
|
export const getCaretPosition = () => {
|
||||||
|
const cursor = editor.getCursor()
|
||||||
|
return {
|
||||||
|
start: cursor.ch,
|
||||||
|
end: cursor.ch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
// Create the editor with initial value
|
||||||
|
createEditor(mode, value)
|
||||||
|
|
||||||
|
// Clean up editor on unmount
|
||||||
|
return () => {
|
||||||
|
if (editor) {
|
||||||
|
editor.toTextArea()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div style={`--code-mirror-height: ${height}px`}>
|
||||||
|
<textarea tabindex="0" bind:this={textarea} readonly {value} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div :global(.CodeMirror) {
|
||||||
|
height: var(--code-mirror-height);
|
||||||
|
font-family: monospace;
|
||||||
|
line-height: 1.3;
|
||||||
|
border: var(--spectrum-alias-border-size-thin) solid;
|
||||||
|
border-color: var(--spectrum-alias-border-color);
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: var(--border-radius-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override default active line highlight colour in dark theme */
|
||||||
|
div
|
||||||
|
:global(.CodeMirror-focused.cm-s-tomorrow-night-eighties
|
||||||
|
.CodeMirror-activeline-background) {
|
||||||
|
background: rgba(255, 255, 255, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove active line styling when not focused */
|
||||||
|
div
|
||||||
|
:global(.CodeMirror:not(.CodeMirror-focused)
|
||||||
|
.CodeMirror-activeline-background) {
|
||||||
|
background: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a spectrum themed border when focused */
|
||||||
|
div :global(.CodeMirror-focused) {
|
||||||
|
border-color: var(--spectrum-alias-border-color-mouse-focus);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,12 +1,22 @@
|
||||||
import CodeMirror from "codemirror"
|
import CodeMirror from "codemirror"
|
||||||
import "codemirror/lib/codemirror.css"
|
import "codemirror/lib/codemirror.css"
|
||||||
import "codemirror/theme/tomorrow-night-eighties.css"
|
|
||||||
import "codemirror/addon/hint/show-hint.css"
|
// Modes
|
||||||
import "codemirror/theme/neo.css"
|
import "codemirror/mode/javascript/javascript"
|
||||||
import "codemirror/mode/sql/sql"
|
import "codemirror/mode/sql/sql"
|
||||||
import "codemirror/mode/css/css"
|
import "codemirror/mode/css/css"
|
||||||
import "codemirror/mode/handlebars/handlebars"
|
import "codemirror/mode/handlebars/handlebars"
|
||||||
import "codemirror/mode/javascript/javascript"
|
|
||||||
|
// Hints
|
||||||
import "codemirror/addon/hint/show-hint"
|
import "codemirror/addon/hint/show-hint"
|
||||||
|
import "codemirror/addon/hint/show-hint.css"
|
||||||
|
|
||||||
|
// Theming
|
||||||
|
import "codemirror/theme/tomorrow-night-eighties.css"
|
||||||
|
|
||||||
|
// Functional addons
|
||||||
|
import "codemirror/addon/selection/active-line"
|
||||||
|
import "codemirror/addon/edit/closebrackets"
|
||||||
|
import "codemirror/addon/edit/matchbrackets"
|
||||||
|
|
||||||
export default CodeMirror
|
export default CodeMirror
|
||||||
|
|
Loading…
Reference in New Issue