anki/ts/editor/mathjax-overlay/MathjaxEditor.svelte
Henrik Giesel 8f8f3bd465
Insert symbols overlay (#2051)
* Add flag for enabling insert symbols feature

* Add symbols overlay directory

* Detect if :xy is inserted into editable

* Allow naive updating of overlay, and special handling of ':'

* First step towards better Virtual Element support

* Update floating to reference range on insert text

* Position SymbolsOverlay always on top or bottom

* Add a data-provider to emulate API

* Show correct suggestions in symbols overlay

* Rename to replacementLength

* Allow replacing via clicking in menu

* Optionally remove inline padding of Popover

* Hide Symbols overlay on blur of content editable

* Add specialKey to inputHandler and generalize how arrow movement is detected

- This way macOS users can use Ctrl-N to mean down, etc.

* Detect special key from within SymbolsOverlay

* Implement full backwards search while typing

* Allow navigating symbol menu and accepting with enter

* Add some entries to data-provider

* Satisfy eslint

* Generate symbolsTable from sources

* Use other github source, allow multiple names

In return, symbol must be unique

* Automatically scroll in symbols dropdown

* Use from npm packages rather than downloading from URL

* Remove console.log

* Remove print

* Add pointerDown event to input-handler

- so that SymbolsOverlay can reset on field click

* Make tab do the same as enter

* Make font a bit smaller but increase relative icon size

* Satisfy type requirement of handlerlist

* Revert changing default size of DropdownItems

* Remove some now unused code for bootstrap dropdowns
2022-09-10 18:46:59 +10:00

133 lines
3.9 KiB
Svelte

<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import type CodeMirrorLib from "codemirror";
import { createEventDispatcher, onMount } from "svelte";
import type { Writable } from "svelte/store";
import * as tr from "../../lib/ftl";
import { noop } from "../../lib/functional";
import { isArrowLeft, isArrowRight } from "../../lib/keys";
import { getPlatformString } from "../../lib/shortcuts";
import { pageTheme } from "../../sveltelib/theme";
import { baseOptions, focusAndSetCaret, latex } from "../code-mirror";
import type { CodeMirrorAPI } from "../CodeMirror.svelte";
import CodeMirror from "../CodeMirror.svelte";
export let code: Writable<string>;
export let acceptShortcut: string;
export let newlineShortcut: string;
const configuration = {
...Object.assign({}, baseOptions, {
extraKeys: {
...(baseOptions.extraKeys as CodeMirrorLib.KeyMap),
[acceptShortcut]: noop,
[newlineShortcut]: noop,
},
}),
placeholder: tr.editingMathjaxPlaceholder({
accept: getPlatformString(acceptShortcut),
newline: getPlatformString(newlineShortcut),
}),
mode: latex,
};
/* These are not reactive, but only operate on initialization */
export let position: CodeMirrorLib.Position | undefined = undefined;
export let selectAll: boolean;
const dispatch = createEventDispatcher();
let codeMirror = {} as CodeMirrorAPI;
onMount(async () => {
const editor = await codeMirror.editor;
let direction: "start" | "end" | undefined = undefined;
editor.on(
"keydown",
(_instance: CodeMirrorLib.Editor, event: KeyboardEvent): void => {
if (isArrowLeft(event)) {
direction = "start";
} else if (isArrowRight(event)) {
direction = "end";
}
},
);
editor.on(
"beforeSelectionChange",
(
instance: CodeMirrorLib.Editor,
obj: CodeMirrorLib.EditorSelectionChange,
): void => {
const { anchor } = obj.ranges[0];
if (anchor["hitSide"]) {
if (instance.getValue().length === 0) {
if (direction) {
dispatch(`moveout${direction}`);
}
} else if (anchor.line === 0 && anchor.ch === 0) {
dispatch("moveoutstart");
} else {
dispatch("moveoutend");
}
}
direction = undefined;
},
);
setTimeout(() => {
focusAndSetCaret(editor, position);
if (selectAll) {
editor.execCommand("selectAll");
}
});
});
</script>
<div class="mathjax-editor" class:light-theme={!$pageTheme.isDark}>
<CodeMirror
{code}
{configuration}
bind:api={codeMirror}
on:change={({ detail: mathjaxText }) => code.set(mathjaxText)}
on:tab
/>
</div>
<slot editor={codeMirror} />
<style lang="scss">
.mathjax-editor {
margin: 0 1px;
overflow: hidden;
:global(.CodeMirror) {
max-width: 28rem;
min-width: 14rem;
margin-bottom: 0.25rem;
}
&.light-theme :global(.CodeMirror) {
border-width: 1px 0;
border-style: solid;
border-color: var(--border);
}
:global(.CodeMirror-placeholder) {
font-family: sans-serif;
font-size: 55%;
text-align: center;
color: var(--slightly-grey-text);
}
}
</style>