forked from tsai/budibase
2 changed files with 160 additions and 4 deletions
@ -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