feat: fix reactivity issues in graphql
This commit is contained in:
@@ -4,19 +4,23 @@ import {
|
|||||||
EditorState,
|
EditorState,
|
||||||
Compartment,
|
Compartment,
|
||||||
EditorSelection,
|
EditorSelection,
|
||||||
TransactionSpec,
|
|
||||||
} from "@codemirror/state"
|
} from "@codemirror/state"
|
||||||
import { Language, LanguageSupport } from "@codemirror/language"
|
import { Language, LanguageSupport } from "@codemirror/language"
|
||||||
import { defaultKeymap } from "@codemirror/commands"
|
import { defaultKeymap } from "@codemirror/commands"
|
||||||
import { Completion, autocompletion } from "@codemirror/autocomplete"
|
import { Completion, autocompletion } from "@codemirror/autocomplete"
|
||||||
import { linter } from "@codemirror/lint"
|
import { linter } from "@codemirror/lint"
|
||||||
|
|
||||||
import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api"
|
import {
|
||||||
|
watch,
|
||||||
|
ref,
|
||||||
|
Ref,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
} from "@nuxtjs/composition-api"
|
||||||
|
|
||||||
import { javascriptLanguage } from "@codemirror/lang-javascript"
|
import { javascriptLanguage } from "@codemirror/lang-javascript"
|
||||||
import { jsonLanguage } from "@codemirror/lang-json"
|
import { jsonLanguage } from "@codemirror/lang-json"
|
||||||
import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql"
|
import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql"
|
||||||
import { onBeforeUnmount } from "@vue/runtime-dom"
|
|
||||||
import { pipe } from "fp-ts/function"
|
import { pipe } from "fp-ts/function"
|
||||||
import * as O from "fp-ts/Option"
|
import * as O from "fp-ts/Option"
|
||||||
import { isJSONContentType } from "../utils/contenttypes"
|
import { isJSONContentType } from "../utils/contenttypes"
|
||||||
@@ -140,105 +144,101 @@ export function useCodemirror(
|
|||||||
line: 0,
|
line: 0,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const cachedValue = ref(value.value)
|
const cachedValue = ref(value.value)
|
||||||
|
|
||||||
const state = EditorState.create({
|
|
||||||
doc: value.value,
|
|
||||||
extensions: [
|
|
||||||
basicSetup,
|
|
||||||
baseTheme,
|
|
||||||
baseHighlightStyle,
|
|
||||||
ViewPlugin.fromClass(
|
|
||||||
class {
|
|
||||||
update(update: ViewUpdate) {
|
|
||||||
if (update.selectionSet) {
|
|
||||||
const cursorPos = update.state.selection.main.head
|
|
||||||
|
|
||||||
const line = update.state.doc.lineAt(cursorPos)
|
|
||||||
|
|
||||||
cachedCursor.value = {
|
|
||||||
line: line.number - 1,
|
|
||||||
ch: cursorPos - line.from,
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor.value = {
|
|
||||||
line: cachedCursor.value.line,
|
|
||||||
ch: cachedCursor.value.ch,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (update.docChanged) {
|
|
||||||
// Expensive on big files ?
|
|
||||||
console.log("doc change")
|
|
||||||
cachedValue.value = update.state.doc
|
|
||||||
.toJSON()
|
|
||||||
.join(update.state.lineBreak)
|
|
||||||
value.value = cachedValue.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
EditorState.changeFilter.of(() => !options.extendedEditorConfig.readOnly),
|
|
||||||
language.of(
|
|
||||||
getEditorLanguage(
|
|
||||||
options.extendedEditorConfig.mode ?? "",
|
|
||||||
options.linter ?? undefined,
|
|
||||||
options.completer ?? undefined
|
|
||||||
)
|
|
||||||
),
|
|
||||||
lineWrapping.of(
|
|
||||||
options.extendedEditorConfig.lineWrapping
|
|
||||||
? [EditorView.lineWrapping]
|
|
||||||
: []
|
|
||||||
),
|
|
||||||
keymap.of(defaultKeymap),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
const view = ref<EditorView>()
|
const view = ref<EditorView>()
|
||||||
|
|
||||||
const dispatch = (t: TransactionSpec) =>
|
const initView = (el: any) => {
|
||||||
view.value ? view.value.dispatch(t) : state.update(t)
|
view.value = new EditorView({
|
||||||
|
parent: el,
|
||||||
|
state: EditorState.create({
|
||||||
|
doc: value.value,
|
||||||
|
extensions: [
|
||||||
|
basicSetup,
|
||||||
|
baseTheme,
|
||||||
|
baseHighlightStyle,
|
||||||
|
ViewPlugin.fromClass(
|
||||||
|
class {
|
||||||
|
update(update: ViewUpdate) {
|
||||||
|
if (update.selectionSet) {
|
||||||
|
const cursorPos = update.state.selection.main.head
|
||||||
|
|
||||||
|
const line = update.state.doc.lineAt(cursorPos)
|
||||||
|
|
||||||
|
cachedCursor.value = {
|
||||||
|
line: line.number - 1,
|
||||||
|
ch: cursorPos - line.from,
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.value = {
|
||||||
|
line: cachedCursor.value.line,
|
||||||
|
ch: cachedCursor.value.ch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update.docChanged) {
|
||||||
|
// Expensive on big files ?
|
||||||
|
console.log("doc change")
|
||||||
|
cachedValue.value = update.state.doc
|
||||||
|
.toJSON()
|
||||||
|
.join(update.state.lineBreak)
|
||||||
|
value.value = cachedValue.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
EditorState.changeFilter.of(
|
||||||
|
() => !options.extendedEditorConfig.readOnly
|
||||||
|
),
|
||||||
|
language.of(
|
||||||
|
getEditorLanguage(
|
||||||
|
options.extendedEditorConfig.mode ?? "",
|
||||||
|
options.linter ?? undefined,
|
||||||
|
options.completer ?? undefined
|
||||||
|
)
|
||||||
|
),
|
||||||
|
lineWrapping.of(
|
||||||
|
options.extendedEditorConfig.lineWrapping
|
||||||
|
? [EditorView.lineWrapping]
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
keymap.of(defaultKeymap),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
view.value = new EditorView({
|
if (el.value) {
|
||||||
state,
|
if (!view.value) initView(el.value)
|
||||||
parent: el.value,
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(el, () => {
|
||||||
|
if (el.value) {
|
||||||
|
if (!view.value) initView(el.value)
|
||||||
|
} else {
|
||||||
|
view.value?.destroy()
|
||||||
|
view.value = undefined
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (view.value) view.value.destroy()
|
view.value?.destroy()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(cursor, (newPos) => {
|
watch(value, (newVal) => {
|
||||||
if (
|
if (cachedValue.value !== newVal) {
|
||||||
cachedCursor.value.line !== newPos.line ||
|
view.value?.dispatch({
|
||||||
cachedCursor.value.ch !== newPos.ch
|
changes: {
|
||||||
) {
|
from: 0,
|
||||||
const line = state.doc.line(newPos.line + 1)
|
to: view.value.state.doc.length,
|
||||||
const selUpdate = EditorSelection.cursor(line.from + newPos.ch - 1)
|
insert: newVal,
|
||||||
|
},
|
||||||
view.value?.focus()
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
scrollIntoView: true,
|
|
||||||
selection: selUpdate,
|
|
||||||
effects: EditorView.scrollTo.of(selUpdate),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
|
||||||
() => options.extendedEditorConfig.lineWrapping,
|
|
||||||
(newMode) => {
|
|
||||||
dispatch({
|
|
||||||
effects: lineWrapping.reconfigure(
|
|
||||||
newMode ? [EditorView.lineWrapping] : []
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
options.extendedEditorConfig.mode,
|
options.extendedEditorConfig.mode,
|
||||||
@@ -246,7 +246,7 @@ export function useCodemirror(
|
|||||||
options.completer,
|
options.completer,
|
||||||
],
|
],
|
||||||
() => {
|
() => {
|
||||||
dispatch({
|
view.value?.dispatch({
|
||||||
effects: language.reconfigure(
|
effects: language.reconfigure(
|
||||||
getEditorLanguage(
|
getEditorLanguage(
|
||||||
(options.extendedEditorConfig.mode as any) ?? "",
|
(options.extendedEditorConfig.mode as any) ?? "",
|
||||||
@@ -258,29 +258,34 @@ export function useCodemirror(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(el, (newEl) => {
|
watch(
|
||||||
|
() => options.extendedEditorConfig.lineWrapping,
|
||||||
|
(newMode) => {
|
||||||
|
view.value?.dispatch({
|
||||||
|
effects: lineWrapping.reconfigure(
|
||||||
|
newMode ? [EditorView.lineWrapping] : []
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(cursor, (newPos) => {
|
||||||
if (view.value) {
|
if (view.value) {
|
||||||
view.value.destroy()
|
if (
|
||||||
view.value = undefined
|
cachedCursor.value.line !== newPos.line ||
|
||||||
}
|
cachedCursor.value.ch !== newPos.ch
|
||||||
|
) {
|
||||||
|
const line = view.value.state.doc.line(newPos.line + 1)
|
||||||
|
const selUpdate = EditorSelection.cursor(line.from + newPos.ch - 1)
|
||||||
|
|
||||||
if (newEl) {
|
view.value?.focus()
|
||||||
view.value = new EditorView({
|
|
||||||
state,
|
|
||||||
parent: newEl,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(value, (newVal) => {
|
view.value.dispatch({
|
||||||
if (cachedValue.value !== newVal) {
|
scrollIntoView: true,
|
||||||
dispatch({
|
selection: selUpdate,
|
||||||
changes: {
|
effects: EditorView.scrollTo.of(selUpdate),
|
||||||
from: 0,
|
})
|
||||||
to: state.doc.length,
|
}
|
||||||
insert: newVal,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user