163 lines
3.9 KiB
Svelte
163 lines
3.9 KiB
Svelte
<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 { Label } from "@budibase/bbui"
|
|
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 resize = "none"
|
|
export let readonly = false
|
|
export let hints = []
|
|
export let label
|
|
|
|
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>
|
|
|
|
{#if label}
|
|
<div style="margin-bottom: var(--spacing-s)">
|
|
<Label small>{label}</Label>
|
|
</div>
|
|
{/if}
|
|
<div
|
|
style={`--code-mirror-height: ${height}px; --code-mirror-resize: ${resize}`}
|
|
>
|
|
<textarea tabindex="0" bind:this={textarea} readonly {value} />
|
|
</div>
|
|
|
|
<style>
|
|
div :global(.CodeMirror) {
|
|
height: var(--code-mirror-height);
|
|
min-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);
|
|
border-radius: var(--border-radius-s);
|
|
resize: var(--code-mirror-resize);
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Ensure hints are always on top */
|
|
:global(.CodeMirror-hints) {
|
|
z-index: 999999;
|
|
}
|
|
</style>
|