@scalar/use-codemirror 0.11.101 → 0.11.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useCodeMirror.ts"],
4
+ "sourcesContent": ["import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete'\nimport { indentWithTab, insertNewline } from '@codemirror/commands'\nimport { css } from '@codemirror/lang-css'\nimport { html } from '@codemirror/lang-html'\nimport { json } from '@codemirror/lang-json'\nimport { xml } from '@codemirror/lang-xml'\nimport { yaml } from '@codemirror/lang-yaml'\nimport {\n type LanguageSupport,\n type StreamLanguage,\n bracketMatching,\n defaultHighlightStyle,\n foldGutter,\n indentOnInput,\n syntaxHighlighting,\n} from '@codemirror/language'\nimport { type Diagnostic, linter } from '@codemirror/lint'\nimport { type Extension, StateEffect } from '@codemirror/state'\nimport {\n EditorView,\n type KeyBinding,\n highlightSpecialChars,\n keymap,\n lineNumbers as lineNumbersExtension,\n placeholder as placeholderExtension,\n} from '@codemirror/view'\nimport { history, historyKeymap } from '@codemirror/commands'\nimport { ScalarIcon } from '@scalar/components'\nimport { type MaybeRefOrGetter, type Ref, computed, h, onBeforeUnmount, ref, render, toValue, watch } from 'vue'\n\nimport { customTheme } from '../themes'\nimport type { CodeMirrorLanguage } from '../types'\nimport { variables } from './variables'\n\ntype BaseParameters = {\n /** Element Ref to mount codemirror to */\n codeMirrorRef: Ref<HTMLDivElement | null>\n /** List of optional extensions for the instance */\n extensions?: MaybeRefOrGetter<Extension[]>\n /** Whether to load a theme.*/\n withoutTheme?: MaybeRefOrGetter<boolean | undefined>\n /** Languages to support for syntax highlighting */\n language: MaybeRefOrGetter<CodeMirrorLanguage | undefined>\n /** Class names to apply to the instance */\n classes?: MaybeRefOrGetter<string[] | undefined>\n /** Put the editor into read-only mode */\n readOnly?: MaybeRefOrGetter<boolean | undefined>\n /** Disable indent with tab */\n disableTabIndent?: MaybeRefOrGetter<boolean | undefined>\n /** Option to show line numbers in the editor */\n lineNumbers?: MaybeRefOrGetter<boolean | undefined>\n withVariables?: MaybeRefOrGetter<boolean | undefined>\n forceFoldGutter?: MaybeRefOrGetter<boolean | undefined>\n disableEnter?: MaybeRefOrGetter<boolean | undefined>\n disableCloseBrackets?: MaybeRefOrGetter<boolean | undefined>\n /** Option to lint and show error in the editor */\n lint?: MaybeRefOrGetter<boolean | undefined>\n onBlur?: (v: string) => void\n onFocus?: (v: string) => void\n placeholder?: MaybeRefOrGetter<string | undefined>\n}\n\nexport type UseCodeMirrorParameters =\n | (BaseParameters & {\n /** Prefill the content. Will be ignored when a provider is given. */\n content: MaybeRefOrGetter<string | undefined>\n onChange?: (v: string) => void\n })\n | (BaseParameters & {\n provider: MaybeRefOrGetter<Extension | null>\n content?: MaybeRefOrGetter<string | undefined>\n onChange?: (v: string) => void\n })\n\n/** Check if the hook has a provider. In provider mode we ignore the content variable */\nconst hasProvider = (\n params: UseCodeMirrorParameters,\n): params is BaseParameters & {\n content?: MaybeRefOrGetter<string | undefined>\n provider: MaybeRefOrGetter<Extension>\n} => 'provider' in params && !!toValue(params.provider)\n\nconst selectAllKeyBinding: KeyBinding = {\n key: 'Mod-a',\n run: (view) => {\n // Select the entire content\n view.dispatch({\n selection: { anchor: 0, head: view.state.doc.length },\n scrollIntoView: false,\n })\n return true\n },\n}\n\n/** Reactive CodeMirror Integration */\nexport const useCodeMirror = (\n params: UseCodeMirrorParameters,\n): {\n setCodeMirrorContent: (content?: string) => void\n codeMirror: Ref<EditorView | null>\n} => {\n const codeMirror: Ref<EditorView | null> = ref(null)\n\n /** Set the codemirror content value */\n const setCodeMirrorContent = (newValue = '') => {\n if (!codeMirror.value) {\n return\n }\n\n // No need to set the CodeMirror content if nothing has changed\n if (codeMirror.value.state.doc.toString() === newValue) {\n return\n }\n\n codeMirror.value.dispatch({\n changes: {\n from: 0,\n to: codeMirror.value.state.doc.length,\n insert: newValue,\n },\n selection: {\n anchor: Math.min(codeMirror.value.state.selection.main.anchor, newValue.length),\n },\n })\n }\n\n // All options except provider\n const extensionConfig = computed(() => ({\n onChange: params.onChange,\n onBlur: params.onBlur,\n onFocus: params.onFocus,\n disableTabIndent: toValue(params.disableTabIndent),\n language: toValue(params.language),\n classes: toValue(params.classes),\n readOnly: toValue(params.readOnly),\n lineNumbers: toValue(params.lineNumbers),\n withVariables: toValue(params.withVariables),\n forceFoldGutter: toValue(params.forceFoldGutter),\n disableEnter: toValue(params.disableEnter),\n disableCloseBrackets: toValue(params.disableCloseBrackets),\n withoutTheme: toValue(params.withoutTheme),\n lint: toValue(params.lint),\n additionalExtensions: toValue(params.extensions),\n placeholder: toValue(params.placeholder),\n }))\n\n // Unmounts CodeMirror if it\u2019s mounted already, and mounts CodeMirror, if the given ref exists.\n watch(\n params.codeMirrorRef,\n () => {\n codeMirror.value?.destroy()\n mountCodeMirror()\n },\n { immediate: true },\n )\n\n // Cleanup codemirror\n onBeforeUnmount(() => codeMirror.value?.destroy())\n\n // Initializes CodeMirror.\n function mountCodeMirror() {\n if (params.codeMirrorRef.value) {\n const provider = hasProvider(params) ? toValue(params.provider) : null\n const extensions = getCodeMirrorExtensions({\n ...extensionConfig.value,\n provider,\n })\n\n codeMirror.value = new EditorView({\n parent: params.codeMirrorRef.value,\n extensions,\n })\n\n // Set the initial content if a provider is not in use\n if (!hasProvider(params)) {\n setCodeMirrorContent(toValue(params.content))\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n\n // Provider must be watched separately because we need to restart codemirror if the provider changes\n watch(\n () => (hasProvider(params) ? toValue(params.provider) : null),\n () => {\n if (hasProvider(params)) {\n codeMirror.value?.destroy()\n mountCodeMirror()\n }\n },\n )\n\n // Update the extensions whenever parameters changes\n watch(\n extensionConfig,\n () => {\n if (!codeMirror.value) {\n return\n }\n // If a provider is\n\n const provider = hasProvider(params) ? toValue(params.provider) : null\n const extensions = getCodeMirrorExtensions({\n ...extensionConfig.value,\n provider,\n })\n\n requestAnimationFrame(() => {\n codeMirror.value?.dispatch({\n effects: StateEffect.reconfigure.of(extensions),\n })\n })\n },\n { immediate: true },\n )\n\n // ---------------------------------------------------------------------------\n\n // Keep the content in sync when the content is managed externally\n watch(\n () => toValue(params.content),\n () => {\n // When a provider is in use we do not map the content value back to the codemirror instance\n if (hasProvider(params)) {\n return\n }\n\n setCodeMirrorContent(toValue(params.content))\n },\n { immediate: true },\n )\n\n return {\n /** Replaces the current content with the given value. */\n setCodeMirrorContent,\n /** Codemirror instance */\n codeMirror,\n }\n}\n\n// ---------------------------------------------------------------------------\n\nconst languageExtensions: {\n [lang in CodeMirrorLanguage]: () => LanguageSupport | StreamLanguage<any>\n} = {\n html: html,\n json: json,\n yaml: yaml,\n css: css,\n xml: xml,\n}\n\n/** Generate the list of extension from parameters */\nfunction getCodeMirrorExtensions({\n onChange,\n onBlur,\n onFocus,\n provider,\n language,\n classes = [],\n readOnly = false,\n lineNumbers = false,\n withVariables = false,\n forceFoldGutter = false,\n disableEnter = false,\n disableCloseBrackets = false,\n disableTabIndent = false,\n withoutTheme = false,\n lint = false,\n additionalExtensions = [],\n placeholder,\n}: {\n classes?: string[]\n language?: CodeMirrorLanguage\n readOnly?: boolean\n lineNumbers?: boolean\n disableCloseBrackets?: boolean\n disableTabIndent?: boolean\n withVariables?: boolean\n disableEnter?: boolean\n forceFoldGutter?: boolean\n onChange?: (val: string) => void\n onFocus?: (val: string) => void\n onBlur?: (val: string) => void\n withoutTheme?: boolean\n provider: Extension | null\n lint?: boolean\n additionalExtensions?: Extension[]\n placeholder?: string\n}) {\n const extensions: Extension[] = [\n highlightSpecialChars(),\n history(),\n keymap.of(historyKeymap),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n EditorView.theme({\n '.cm-line': {\n lineHeight: '20px',\n padding: '0 2px 0 4px',\n },\n '.cm-gutterElement': {\n lineHeight: '20px',\n },\n '.cm-tooltip': {\n border: '1px solid #f5c6cb',\n fontSize: '12px',\n },\n '.cm-tooltip-lint': {\n backgroundColor: '#ffffff',\n },\n '.cm-diagnostic-error': {\n borderLeft: '0',\n color: '#dc1b19',\n },\n '.cm-foldPlaceholder': {\n background: 'var(--scalar-background-1)',\n border: 'none',\n fontFamily: 'var(--scalar-font)',\n },\n }),\n // Listen to updates\n EditorView.updateListener.of((v) => {\n if (!v.docChanged) {\n return\n }\n onChange?.(v.state.doc.toString())\n }),\n EditorView.domEventHandlers({\n blur: (_event, view) => {\n onBlur?.(view.state.doc.toString())\n },\n focus: (_event, view) => {\n onFocus?.(view.state.doc.toString())\n },\n }),\n // Add Classes\n EditorView.editorAttributes.of({ class: classes.join(' ') }),\n ...additionalExtensions,\n ]\n\n // Enable the provider\n if (provider) {\n extensions.push(provider)\n }\n\n // Add the theme as needed\n if (!withoutTheme) {\n extensions.push(customTheme)\n }\n\n // Read only\n if (readOnly) {\n extensions.push(EditorView.editable.of(false))\n } else {\n extensions.push(\n indentOnInput(),\n bracketMatching(),\n autocompletion(),\n keymap.of([...completionKeymap, selectAllKeyBinding]),\n bracketMatching(),\n )\n\n if (!disableCloseBrackets) {\n extensions.push(closeBrackets(), keymap.of([...closeBracketsKeymap]))\n }\n\n if (disableTabIndent) {\n extensions.push(\n keymap.of([\n {\n key: 'Tab',\n run: () => false, // Prevent default Tab behavior\n shift: () => false, // Prevent default Shift+Tab behavior\n },\n ]),\n )\n } else {\n extensions.push(keymap.of([indentWithTab]))\n }\n }\n\n // Add placeholder extension if placeholder is provided\n if (placeholder) {\n extensions.push(placeholderExtension(placeholder))\n }\n\n // Line numbers\n if (lineNumbers) {\n extensions.push(lineNumbersExtension())\n }\n\n if (forceFoldGutter) {\n extensions.push(\n foldGutter({\n markerDOM: (open) => {\n const icon = document.createElement('div')\n icon.classList.add('cm-foldMarker')\n const vnode = h(ScalarIcon, {\n icon: open ? 'ChevronDown' : 'ChevronRight',\n size: 'md',\n })\n render(vnode, icon)\n return icon\n },\n }),\n )\n }\n\n // Syntax highlighting\n if (language && languageExtensions[language]) {\n extensions.push(languageExtensions[language]())\n if (!forceFoldGutter) {\n extensions.push(\n foldGutter({\n markerDOM: (open) => {\n const icon = document.createElement('div')\n icon.classList.add('cm-foldMarker')\n const vnode = h(ScalarIcon, {\n icon: open ? 'ChevronDown' : 'ChevronRight',\n size: 'md',\n })\n render(vnode, icon)\n return icon\n },\n }),\n )\n }\n }\n\n // JSON Linter\n if (lint && language === 'json') {\n const jsonLinter = linter((view) => {\n const diagnostics: Diagnostic[] = []\n const content = view.state.doc.toString()\n if (content.trim()) {\n try {\n JSON.parse(content)\n } catch (e) {\n if (e instanceof Error) {\n diagnostics.push({\n from: 0,\n to: view.state.doc.length,\n severity: 'error',\n message: e.message,\n })\n }\n }\n }\n return diagnostics\n })\n extensions.push(jsonLinter)\n }\n\n // Highlight variables\n if (withVariables) {\n extensions.push(variables())\n }\n\n if (disableEnter) {\n extensions.push(\n keymap.of([\n {\n key: 'Enter',\n run: () => {\n return true\n },\n },\n {\n key: 'Ctrl-Enter',\n mac: 'Cmd-Enter',\n run: () => {\n return true\n },\n },\n {\n key: 'Shift-Enter',\n run: () => {\n return true\n },\n },\n ]),\n )\n } else {\n extensions.push(\n keymap.of([\n {\n key: 'Enter',\n run: insertNewline,\n },\n ]),\n )\n }\n\n return extensions\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,69 @@
1
+ import { EditorView } from "@codemirror/view";
2
+ import { describe, expect, it } from "vitest";
3
+ import { ref } from "vue";
4
+ import { useCodeMirror } from "../hooks/useCodeMirror.js";
5
+ describe("useCodeMirror", () => {
6
+ it("should initialize with basic configuration", () => {
7
+ const codeMirrorRef = ref(document.createElement("div"));
8
+ const { codeMirror } = useCodeMirror({
9
+ codeMirrorRef,
10
+ content: "",
11
+ language: void 0
12
+ });
13
+ expect(codeMirror.value).not.toBeNull();
14
+ });
15
+ it("should update content when content prop changes", () => {
16
+ const codeMirrorRef = ref(document.createElement("div"));
17
+ const { codeMirror, setCodeMirrorContent } = useCodeMirror({
18
+ codeMirrorRef,
19
+ content: "initial",
20
+ language: void 0
21
+ });
22
+ setCodeMirrorContent("updated content");
23
+ expect(codeMirror.value?.state.doc.toString()).toBe("updated content");
24
+ });
25
+ it("should handle read-only mode", () => {
26
+ const codeMirrorRef = ref(document.createElement("div"));
27
+ const { codeMirror } = useCodeMirror({
28
+ codeMirrorRef,
29
+ content: "test content",
30
+ language: void 0,
31
+ readOnly: true
32
+ });
33
+ expect(codeMirror.value?.state.facet(EditorView.editable)).toBe(false);
34
+ });
35
+ it("should support different languages", () => {
36
+ const codeMirrorRef = ref(document.createElement("div"));
37
+ const { codeMirror } = useCodeMirror({
38
+ codeMirrorRef,
39
+ content: '{"test": "json"}',
40
+ language: "json"
41
+ });
42
+ expect(codeMirror.value).not.toBeNull();
43
+ });
44
+ it("should trigger onChange callback", () => {
45
+ let changedContent = "";
46
+ const codeMirrorRef = ref(document.createElement("div"));
47
+ const { setCodeMirrorContent } = useCodeMirror({
48
+ codeMirrorRef,
49
+ content: "initial",
50
+ language: void 0,
51
+ onChange: (content) => {
52
+ changedContent = content;
53
+ }
54
+ });
55
+ setCodeMirrorContent("new content");
56
+ expect(changedContent).toBe("new content");
57
+ });
58
+ it("should handle placeholder text", () => {
59
+ const codeMirrorRef = ref(document.createElement("div"));
60
+ const { codeMirror } = useCodeMirror({
61
+ codeMirrorRef,
62
+ content: "",
63
+ language: void 0,
64
+ placeholder: "Type something..."
65
+ });
66
+ expect(codeMirror.value?.dom.querySelector(".cm-placeholder")).not.toBeNull();
67
+ });
68
+ });
69
+ //# sourceMappingURL=useCodeMirror.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useCodeMirror.test.ts"],
4
+ "sourcesContent": ["// @vitest-environment jsdom\nimport { EditorView } from '@codemirror/view'\nimport { describe, expect, it } from 'vitest'\nimport { ref } from 'vue'\n\nimport { useCodeMirror } from '../hooks/useCodeMirror'\n\ndescribe('useCodeMirror', () => {\n it('should initialize with basic configuration', () => {\n const codeMirrorRef = ref(document.createElement('div'))\n const { codeMirror } = useCodeMirror({\n codeMirrorRef,\n content: '',\n language: undefined,\n })\n expect(codeMirror.value).not.toBeNull()\n })\n\n it('should update content when content prop changes', () => {\n const codeMirrorRef = ref(document.createElement('div'))\n const { codeMirror, setCodeMirrorContent } = useCodeMirror({\n codeMirrorRef,\n content: 'initial',\n language: undefined,\n })\n\n setCodeMirrorContent('updated content')\n expect(codeMirror.value?.state.doc.toString()).toBe('updated content')\n })\n\n it('should handle read-only mode', () => {\n const codeMirrorRef = ref(document.createElement('div'))\n const { codeMirror } = useCodeMirror({\n codeMirrorRef,\n content: 'test content',\n language: undefined,\n readOnly: true,\n })\n\n expect(codeMirror.value?.state.facet(EditorView.editable)).toBe(false)\n })\n\n it('should support different languages', () => {\n const codeMirrorRef = ref(document.createElement('div'))\n const { codeMirror } = useCodeMirror({\n codeMirrorRef,\n content: '{\"test\": \"json\"}',\n language: 'json',\n })\n\n expect(codeMirror.value).not.toBeNull()\n })\n\n it('should trigger onChange callback', () => {\n let changedContent = ''\n const codeMirrorRef = ref(document.createElement('div'))\n const { setCodeMirrorContent } = useCodeMirror({\n codeMirrorRef,\n content: 'initial',\n language: undefined,\n onChange: (content) => {\n changedContent = content\n },\n })\n\n setCodeMirrorContent('new content')\n expect(changedContent).toBe('new content')\n })\n\n it('should handle placeholder text', () => {\n const codeMirrorRef = ref(document.createElement('div'))\n const { codeMirror } = useCodeMirror({\n codeMirrorRef,\n content: '',\n language: undefined,\n placeholder: 'Type something...',\n })\n\n expect(codeMirror.value?.dom.querySelector('.cm-placeholder')).not.toBeNull()\n })\n})\n"],
5
+ "mappings": "AACA,SAAS,kBAAkB;AAC3B,SAAS,UAAU,QAAQ,UAAU;AACrC,SAAS,WAAW;AAEpB,SAAS,qBAAqB;AAE9B,SAAS,iBAAiB,MAAM;AAC9B,KAAG,8CAA8C,MAAM;AACrD,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,WAAW,IAAI,cAAc;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AACD,WAAO,WAAW,KAAK,EAAE,IAAI,SAAS;AAAA,EACxC,CAAC;AAED,KAAG,mDAAmD,MAAM;AAC1D,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,YAAY,qBAAqB,IAAI,cAAc;AAAA,MACzD;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AAED,yBAAqB,iBAAiB;AACtC,WAAO,WAAW,OAAO,MAAM,IAAI,SAAS,CAAC,EAAE,KAAK,iBAAiB;AAAA,EACvE,CAAC;AAED,KAAG,gCAAgC,MAAM;AACvC,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,WAAW,IAAI,cAAc;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAED,WAAO,WAAW,OAAO,MAAM,MAAM,WAAW,QAAQ,CAAC,EAAE,KAAK,KAAK;AAAA,EACvE,CAAC;AAED,KAAG,sCAAsC,MAAM;AAC7C,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,WAAW,IAAI,cAAc;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AAED,WAAO,WAAW,KAAK,EAAE,IAAI,SAAS;AAAA,EACxC,CAAC;AAED,KAAG,oCAAoC,MAAM;AAC3C,QAAI,iBAAiB;AACrB,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,qBAAqB,IAAI,cAAc;AAAA,MAC7C;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU,CAAC,YAAY;AACrB,yBAAiB;AAAA,MACnB;AAAA,IACF,CAAC;AAED,yBAAqB,aAAa;AAClC,WAAO,cAAc,EAAE,KAAK,aAAa;AAAA,EAC3C,CAAC;AAED,KAAG,kCAAkC,MAAM;AACzC,UAAM,gBAAgB,IAAI,SAAS,cAAc,KAAK,CAAC;AACvD,UAAM,EAAE,WAAW,IAAI,cAAc;AAAA,MACnC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAED,WAAO,WAAW,OAAO,IAAI,cAAc,iBAAiB,CAAC,EAAE,IAAI,SAAS;AAAA,EAC9E,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -1,65 +1,58 @@
1
- import { watch } from 'vue';
2
-
3
- /** Custom hook to manage a dropdown in a CodeMirror editor */
1
+ import { watch } from "vue";
4
2
  function useDropdown(params) {
5
- const { codeMirror, query, showDropdown, dropdownPosition } = params;
6
- function getCursorPos() {
7
- return codeMirror.value?.state.selection.main.head || 0;
3
+ const { codeMirror, query, showDropdown, dropdownPosition } = params;
4
+ function getCursorPos() {
5
+ return codeMirror.value?.state.selection.main.head || 0;
6
+ }
7
+ function getCoordsAtPos(pos) {
8
+ return codeMirror.value?.coordsAtPos(pos);
9
+ }
10
+ function updateDropdownPosition() {
11
+ const cursorPos = getCursorPos();
12
+ requestAnimationFrame(() => {
13
+ const coords = getCoordsAtPos(cursorPos - query.value.length - 2);
14
+ if (coords) {
15
+ dropdownPosition.value = {
16
+ left: coords.left,
17
+ top: Math.max(coords.bottom)
18
+ };
19
+ }
20
+ });
21
+ }
22
+ watch(query, updateDropdownPosition);
23
+ function handleDropdownSelect(item) {
24
+ const formattedItem = `{{${item}}}`;
25
+ const cursor = getCursorPos();
26
+ const from = Math.max(0, cursor - query.value.length - 2);
27
+ const to = cursor;
28
+ codeMirror.value?.dispatch({
29
+ changes: { from, to, insert: formattedItem }
30
+ });
31
+ showDropdown.value = false;
32
+ }
33
+ function updateDropdownVisibility() {
34
+ const cursor = getCursorPos();
35
+ const text = codeMirror.value?.state.doc.sliceString(0, cursor) || "";
36
+ const lastOpenBraceIndex = text.lastIndexOf("{{");
37
+ const lastCloseBraceIndex = text.lastIndexOf("}}");
38
+ if (lastOpenBraceIndex > lastCloseBraceIndex) {
39
+ query.value = text.slice(lastOpenBraceIndex + 2);
40
+ showDropdown.value = true;
41
+ dropdownPosition.value = getCoordsAtPos(cursor) || { left: 0, top: 0 };
42
+ if (query.value === "") {
43
+ updateDropdownPosition();
44
+ }
45
+ } else {
46
+ showDropdown.value = false;
8
47
  }
9
- function getCoordsAtPos(pos) {
10
- return codeMirror.value?.coordsAtPos(pos);
11
- }
12
- /** Updates position of the dropdown based on the current cursor position */
13
- function updateDropdownPosition() {
14
- const cursorPos = getCursorPos();
15
- requestAnimationFrame(() => {
16
- const coords = getCoordsAtPos(cursorPos - query.value.length - 2);
17
- if (coords) {
18
- dropdownPosition.value = {
19
- left: coords.left,
20
- top: Math.max(coords.bottom),
21
- };
22
- }
23
- });
24
- }
25
- // Watch for changes in the query and update the dropdown position
26
- watch(query, updateDropdownPosition);
27
- /** Inserts selected item at the current cursor position */
28
- function handleDropdownSelect(item) {
29
- const formattedItem = `{{${item}}}`;
30
- const cursor = getCursorPos();
31
- const from = Math.max(0, cursor - query.value.length - 2);
32
- const to = cursor;
33
- codeMirror.value?.dispatch({
34
- changes: { from, to, insert: formattedItem },
35
- });
36
- showDropdown.value = false;
37
- }
38
- /** Updates dropdown visibility based on current cursor position */
39
- function updateDropdownVisibility() {
40
- const cursor = getCursorPos();
41
- const text = codeMirror.value?.state.doc.sliceString(0, cursor) || '';
42
- const lastOpenBraceIndex = text.lastIndexOf('{{');
43
- const lastCloseBraceIndex = text.lastIndexOf('}}');
44
- if (lastOpenBraceIndex > lastCloseBraceIndex) {
45
- query.value = text.slice(lastOpenBraceIndex + 2);
46
- showDropdown.value = true;
47
- dropdownPosition.value = getCoordsAtPos(cursor) || { left: 0, top: 0 };
48
- // Ensures dropdown position even if the query is empty
49
- if (query.value === '') {
50
- updateDropdownPosition();
51
- }
52
- }
53
- else {
54
- showDropdown.value = false;
55
- }
56
- }
57
- // Watch for changes in the content and update the dropdown visibility
58
- watch(() => codeMirror.value?.state.doc.toString(), updateDropdownVisibility);
59
- return {
60
- handleDropdownSelect,
61
- updateDropdownVisibility,
62
- };
48
+ }
49
+ watch(() => codeMirror.value?.state.doc.toString(), updateDropdownVisibility);
50
+ return {
51
+ handleDropdownSelect,
52
+ updateDropdownVisibility
53
+ };
63
54
  }
64
-
65
- export { useDropdown };
55
+ export {
56
+ useDropdown
57
+ };
58
+ //# sourceMappingURL=useDropdown.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useDropdown.ts"],
4
+ "sourcesContent": ["import type { EditorView } from '@codemirror/view'\nimport { type Ref, watch } from 'vue'\n\n/** Custom hook to manage a dropdown in a CodeMirror editor */\nexport function useDropdown(params: {\n codeMirror: Ref<EditorView | null>\n onSelect?: (item: string) => void\n query: Ref<string>\n showDropdown: Ref<boolean>\n dropdownPosition: Ref<{ left: number; top: number }>\n}) {\n const { codeMirror, query, showDropdown, dropdownPosition } = params\n\n function getCursorPos() {\n return codeMirror.value?.state.selection.main.head || 0\n }\n\n function getCoordsAtPos(pos: number) {\n return codeMirror.value?.coordsAtPos(pos)\n }\n\n /** Updates position of the dropdown based on the current cursor position */\n function updateDropdownPosition() {\n const cursorPos = getCursorPos()\n requestAnimationFrame(() => {\n const coords = getCoordsAtPos(cursorPos - query.value.length - 2)\n if (coords) {\n dropdownPosition.value = {\n left: coords.left,\n top: Math.max(coords.bottom),\n }\n }\n })\n }\n\n // Watch for changes in the query and update the dropdown position\n watch(query, updateDropdownPosition)\n\n /** Inserts selected item at the current cursor position */\n function handleDropdownSelect(item: string) {\n const formattedItem = `{{${item}}}`\n const cursor = getCursorPos()\n const from = Math.max(0, cursor - query.value.length - 2)\n const to = cursor\n codeMirror.value?.dispatch({\n changes: { from, to, insert: formattedItem },\n })\n showDropdown.value = false\n }\n\n /** Updates dropdown visibility based on current cursor position */\n function updateDropdownVisibility() {\n const cursor = getCursorPos()\n const text = codeMirror.value?.state.doc.sliceString(0, cursor) || ''\n const lastOpenBraceIndex = text.lastIndexOf('{{')\n const lastCloseBraceIndex = text.lastIndexOf('}}')\n if (lastOpenBraceIndex > lastCloseBraceIndex) {\n query.value = text.slice(lastOpenBraceIndex + 2)\n showDropdown.value = true\n dropdownPosition.value = getCoordsAtPos(cursor) || { left: 0, top: 0 }\n // Ensures dropdown position even if the query is empty\n if (query.value === '') {\n updateDropdownPosition()\n }\n } else {\n showDropdown.value = false\n }\n }\n\n // Watch for changes in the content and update the dropdown visibility\n watch(() => codeMirror.value?.state.doc.toString(), updateDropdownVisibility)\n\n return {\n handleDropdownSelect,\n updateDropdownVisibility,\n }\n}\n"],
5
+ "mappings": "AACA,SAAmB,aAAa;AAGzB,SAAS,YAAY,QAMzB;AACD,QAAM,EAAE,YAAY,OAAO,cAAc,iBAAiB,IAAI;AAE9D,WAAS,eAAe;AACtB,WAAO,WAAW,OAAO,MAAM,UAAU,KAAK,QAAQ;AAAA,EACxD;AAEA,WAAS,eAAe,KAAa;AACnC,WAAO,WAAW,OAAO,YAAY,GAAG;AAAA,EAC1C;AAGA,WAAS,yBAAyB;AAChC,UAAM,YAAY,aAAa;AAC/B,0BAAsB,MAAM;AAC1B,YAAM,SAAS,eAAe,YAAY,MAAM,MAAM,SAAS,CAAC;AAChE,UAAI,QAAQ;AACV,yBAAiB,QAAQ;AAAA,UACvB,MAAM,OAAO;AAAA,UACb,KAAK,KAAK,IAAI,OAAO,MAAM;AAAA,QAC7B;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,OAAO,sBAAsB;AAGnC,WAAS,qBAAqB,MAAc;AAC1C,UAAM,gBAAgB,KAAK,IAAI;AAC/B,UAAM,SAAS,aAAa;AAC5B,UAAM,OAAO,KAAK,IAAI,GAAG,SAAS,MAAM,MAAM,SAAS,CAAC;AACxD,UAAM,KAAK;AACX,eAAW,OAAO,SAAS;AAAA,MACzB,SAAS,EAAE,MAAM,IAAI,QAAQ,cAAc;AAAA,IAC7C,CAAC;AACD,iBAAa,QAAQ;AAAA,EACvB;AAGA,WAAS,2BAA2B;AAClC,UAAM,SAAS,aAAa;AAC5B,UAAM,OAAO,WAAW,OAAO,MAAM,IAAI,YAAY,GAAG,MAAM,KAAK;AACnE,UAAM,qBAAqB,KAAK,YAAY,IAAI;AAChD,UAAM,sBAAsB,KAAK,YAAY,IAAI;AACjD,QAAI,qBAAqB,qBAAqB;AAC5C,YAAM,QAAQ,KAAK,MAAM,qBAAqB,CAAC;AAC/C,mBAAa,QAAQ;AACrB,uBAAiB,QAAQ,eAAe,MAAM,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE;AAErE,UAAI,MAAM,UAAU,IAAI;AACtB,+BAAuB;AAAA,MACzB;AAAA,IACF,OAAO;AACL,mBAAa,QAAQ;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,MAAM,WAAW,OAAO,MAAM,IAAI,SAAS,GAAG,wBAAwB;AAE5E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1,24 +1,33 @@
1
- import { MatchDecorator, Decoration, ViewPlugin, EditorView } from '@codemirror/view';
2
-
1
+ import {
2
+ Decoration,
3
+ EditorView,
4
+ MatchDecorator,
5
+ ViewPlugin
6
+ } from "@codemirror/view";
3
7
  const variableHighlighterDecoration = new MatchDecorator({
4
- regexp: /(\{[^}]+\})/g,
5
- decoration: () => Decoration.mark({
6
- attributes: {
7
- class: 'api-client-url-variable',
8
- },
9
- }),
8
+ regexp: /(\{[^}]+\})/g,
9
+ decoration: () => Decoration.mark({
10
+ attributes: {
11
+ class: "api-client-url-variable"
12
+ }
13
+ })
10
14
  });
11
- const variables = () => ViewPlugin.fromClass(class {
15
+ const variables = () => ViewPlugin.fromClass(
16
+ class {
12
17
  variables;
13
18
  constructor(view) {
14
- this.variables = variableHighlighterDecoration.createDeco(view);
19
+ this.variables = variableHighlighterDecoration.createDeco(view);
15
20
  }
16
21
  update(update) {
17
- this.variables = variableHighlighterDecoration.updateDeco(update, this.variables);
22
+ this.variables = variableHighlighterDecoration.updateDeco(update, this.variables);
18
23
  }
19
- }, {
24
+ },
25
+ {
20
26
  decorations: (instance) => instance.variables,
21
- provide: (plugin) => EditorView.atomicRanges.of((view) => view.plugin(plugin)?.variables || Decoration.none),
22
- });
23
-
24
- export { variables };
27
+ provide: (plugin) => EditorView.atomicRanges.of((view) => view.plugin(plugin)?.variables || Decoration.none)
28
+ }
29
+ );
30
+ export {
31
+ variables
32
+ };
33
+ //# sourceMappingURL=variables.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/variables.ts"],
4
+ "sourcesContent": ["import {\n Decoration,\n type DecorationSet,\n EditorView,\n MatchDecorator,\n ViewPlugin,\n type ViewUpdate,\n} from '@codemirror/view'\n\nconst variableHighlighterDecoration = new MatchDecorator({\n regexp: /(\\{[^}]+\\})/g,\n decoration: () =>\n Decoration.mark({\n attributes: {\n class: 'api-client-url-variable',\n },\n }),\n})\n\nexport const variables = () =>\n ViewPlugin.fromClass(\n class {\n variables: DecorationSet\n constructor(view: EditorView) {\n this.variables = variableHighlighterDecoration.createDeco(view)\n }\n update(update: ViewUpdate) {\n this.variables = variableHighlighterDecoration.updateDeco(update, this.variables)\n }\n },\n {\n decorations: (instance) => instance.variables,\n provide: (plugin) => EditorView.atomicRanges.of((view) => view.plugin(plugin)?.variables || Decoration.none),\n },\n )\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,MAAM,gCAAgC,IAAI,eAAe;AAAA,EACvD,QAAQ;AAAA,EACR,YAAY,MACV,WAAW,KAAK;AAAA,IACd,YAAY;AAAA,MACV,OAAO;AAAA,IACT;AAAA,EACF,CAAC;AACL,CAAC;AAEM,MAAM,YAAY,MACvB,WAAW;AAAA,EACT,MAAM;AAAA,IACJ;AAAA,IACA,YAAY,MAAkB;AAC5B,WAAK,YAAY,8BAA8B,WAAW,IAAI;AAAA,IAChE;AAAA,IACA,OAAO,QAAoB;AACzB,WAAK,YAAY,8BAA8B,WAAW,QAAQ,KAAK,SAAS;AAAA,IAClF;AAAA,EACF;AAAA,EACA;AAAA,IACE,aAAa,CAAC,aAAa,SAAS;AAAA,IACpC,SAAS,CAAC,WAAW,WAAW,aAAa,GAAG,CAAC,SAAS,KAAK,OAAO,MAAM,GAAG,aAAa,WAAW,IAAI;AAAA,EAC7G;AACF;",
6
+ "names": []
7
+ }
package/dist/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { type Extension, RangeSetBuilder, StateEffect } from '@codemirror/state'
2
2
  export { colorPicker } from '@replit/codemirror-css-color-picker';
3
3
  export { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType, } from '@codemirror/view';
4
4
  export * from './hooks/index.js';
5
- export * from './types';
5
+ export * from './types.js';
6
6
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,20 @@
1
- export { RangeSetBuilder, StateEffect } from '@codemirror/state';
2
- export { colorPicker } from '@replit/codemirror-css-color-picker';
3
- export { Decoration, EditorView, ViewPlugin, WidgetType } from '@codemirror/view';
4
- export { useCodeMirror } from './hooks/useCodeMirror.js';
5
- export { useDropdown } from './hooks/useDropdown.js';
1
+ import { RangeSetBuilder, StateEffect } from "@codemirror/state";
2
+ import { colorPicker } from "@replit/codemirror-css-color-picker";
3
+ import {
4
+ Decoration,
5
+ EditorView,
6
+ ViewPlugin,
7
+ WidgetType
8
+ } from "@codemirror/view";
9
+ export * from "./hooks/index.js";
10
+ export * from "./types.js";
11
+ export {
12
+ Decoration,
13
+ EditorView,
14
+ RangeSetBuilder,
15
+ StateEffect,
16
+ ViewPlugin,
17
+ WidgetType,
18
+ colorPicker
19
+ };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["export { type Extension, RangeSetBuilder, StateEffect } from '@codemirror/state'\nexport { colorPicker } from '@replit/codemirror-css-color-picker'\n\nexport {\n Decoration,\n type DecorationSet,\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n} from '@codemirror/view'\n\nexport * from './hooks'\nexport * from './types'\n"],
5
+ "mappings": "AAAA,SAAyB,iBAAiB,mBAAmB;AAC7D,SAAS,mBAAmB;AAE5B;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AAEP,cAAc;AACd,cAAc;",
6
+ "names": []
7
+ }
@@ -1,85 +1,76 @@
1
- import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
2
- import { EditorView } from '@codemirror/view';
3
-
4
- /**
5
- * This file is copied from @uiw/codemirror-themes.
6
- * We’ve had issues with the import (something to do with CJS/ESM).
7
- *
8
- * @see https://github.com/uiwjs/react-codemirror
9
- * @see https://github.com/scalar/scalar/issues/4222
10
- */
11
- /**
12
- * Creates a CodeMirror theme from a set of options.
13
- */
1
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
2
+ import { EditorView } from "@codemirror/view";
14
3
  const createCodeMirrorTheme = ({ theme, settings = {}, styles = [] }) => {
15
- const themeOptions = {
16
- '.cm-gutters': {},
4
+ const themeOptions = {
5
+ ".cm-gutters": {}
6
+ };
7
+ const baseStyle = {};
8
+ if (settings.background) {
9
+ baseStyle.backgroundColor = settings.background;
10
+ }
11
+ if (settings.backgroundImage) {
12
+ baseStyle.backgroundImage = settings.backgroundImage;
13
+ }
14
+ if (settings.foreground) {
15
+ baseStyle.color = settings.foreground;
16
+ }
17
+ if (settings.fontSize) {
18
+ baseStyle.fontSize = settings.fontSize;
19
+ }
20
+ if (settings.background || settings.foreground) {
21
+ themeOptions["&"] = baseStyle;
22
+ }
23
+ if (settings.fontFamily) {
24
+ themeOptions["&.cm-editor .cm-scroller"] = {
25
+ fontFamily: settings.fontFamily
17
26
  };
18
- const baseStyle = {};
19
- if (settings.background) {
20
- baseStyle.backgroundColor = settings.background;
21
- }
22
- if (settings.backgroundImage) {
23
- baseStyle.backgroundImage = settings.backgroundImage;
24
- }
25
- if (settings.foreground) {
26
- baseStyle.color = settings.foreground;
27
- }
28
- if (settings.fontSize) {
29
- baseStyle.fontSize = settings.fontSize;
30
- }
31
- if (settings.background || settings.foreground) {
32
- themeOptions['&'] = baseStyle;
33
- }
34
- if (settings.fontFamily) {
35
- themeOptions['&.cm-editor .cm-scroller'] = {
36
- fontFamily: settings.fontFamily,
37
- };
38
- }
39
- if (settings.gutterBackground) {
40
- themeOptions['.cm-gutters'].backgroundColor = settings.gutterBackground;
41
- }
42
- if (settings.gutterForeground) {
43
- themeOptions['.cm-gutters'].color = settings.gutterForeground;
44
- }
45
- if (settings.gutterBorder) {
46
- themeOptions['.cm-gutters'].borderRightColor = settings.gutterBorder;
47
- }
48
- if (settings.caret) {
49
- themeOptions['.cm-content'] = {
50
- caretColor: settings.caret,
51
- };
52
- themeOptions['.cm-cursor, .cm-dropCursor'] = {
53
- borderLeftColor: settings.caret,
54
- };
55
- }
56
- const activeLineGutterStyle = {};
57
- if (settings.gutterActiveForeground) {
58
- activeLineGutterStyle.color = settings.gutterActiveForeground;
59
- }
60
- if (settings.lineHighlight) {
61
- themeOptions['.cm-activeLine'] = {
62
- backgroundColor: settings.lineHighlight,
63
- };
64
- activeLineGutterStyle.backgroundColor = settings.lineHighlight;
65
- }
66
- themeOptions['.cm-activeLineGutter'] = activeLineGutterStyle;
67
- if (settings.selection) {
68
- themeOptions['&.cm-focused .cm-selectionBackground, & .cm-line::selection, & .cm-selectionLayer .cm-selectionBackground, .cm-content ::selection'] = {
69
- background: settings.selection + ' !important',
70
- };
71
- }
72
- if (settings.selectionMatch) {
73
- themeOptions['& .cm-selectionMatch'] = {
74
- backgroundColor: settings.selectionMatch,
75
- };
76
- }
77
- const themeExtension = EditorView.theme(themeOptions, {
78
- dark: theme === 'dark',
79
- });
80
- const highlightStyle = HighlightStyle.define(styles);
81
- const extension = [themeExtension, syntaxHighlighting(highlightStyle)];
82
- return extension;
27
+ }
28
+ if (settings.gutterBackground) {
29
+ themeOptions[".cm-gutters"].backgroundColor = settings.gutterBackground;
30
+ }
31
+ if (settings.gutterForeground) {
32
+ themeOptions[".cm-gutters"].color = settings.gutterForeground;
33
+ }
34
+ if (settings.gutterBorder) {
35
+ themeOptions[".cm-gutters"].borderRightColor = settings.gutterBorder;
36
+ }
37
+ if (settings.caret) {
38
+ themeOptions[".cm-content"] = {
39
+ caretColor: settings.caret
40
+ };
41
+ themeOptions[".cm-cursor, .cm-dropCursor"] = {
42
+ borderLeftColor: settings.caret
43
+ };
44
+ }
45
+ const activeLineGutterStyle = {};
46
+ if (settings.gutterActiveForeground) {
47
+ activeLineGutterStyle.color = settings.gutterActiveForeground;
48
+ }
49
+ if (settings.lineHighlight) {
50
+ themeOptions[".cm-activeLine"] = {
51
+ backgroundColor: settings.lineHighlight
52
+ };
53
+ activeLineGutterStyle.backgroundColor = settings.lineHighlight;
54
+ }
55
+ themeOptions[".cm-activeLineGutter"] = activeLineGutterStyle;
56
+ if (settings.selection) {
57
+ themeOptions["&.cm-focused .cm-selectionBackground, & .cm-line::selection, & .cm-selectionLayer .cm-selectionBackground, .cm-content ::selection"] = {
58
+ background: settings.selection + " !important"
59
+ };
60
+ }
61
+ if (settings.selectionMatch) {
62
+ themeOptions["& .cm-selectionMatch"] = {
63
+ backgroundColor: settings.selectionMatch
64
+ };
65
+ }
66
+ const themeExtension = EditorView.theme(themeOptions, {
67
+ dark: theme === "dark"
68
+ });
69
+ const highlightStyle = HighlightStyle.define(styles);
70
+ const extension = [themeExtension, syntaxHighlighting(highlightStyle)];
71
+ return extension;
72
+ };
73
+ export {
74
+ createCodeMirrorTheme
83
75
  };
84
-
85
- export { createCodeMirrorTheme };
76
+ //# sourceMappingURL=createCodeMirrorTheme.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/themes/createCodeMirrorTheme.ts"],
4
+ "sourcesContent": ["/**\n * This file is copied from @uiw/codemirror-themes.\n * We\u2019ve had issues with the import (something to do with CJS/ESM).\n *\n * @see https://github.com/uiwjs/react-codemirror\n * @see https://github.com/scalar/scalar/issues/4222\n */\nimport { HighlightStyle, type TagStyle, syntaxHighlighting } from '@codemirror/language'\nimport type { Extension } from '@codemirror/state'\nimport { EditorView } from '@codemirror/view'\nimport type { StyleSpec } from 'style-mod'\n\nexport type CreateThemeOptions = {\n /**\n * Theme inheritance. Determines which styles CodeMirror will apply by default.\n */\n theme: Theme\n /**\n * Settings to customize the look of the editor, like background, gutter, selection and others.\n */\n settings: Settings\n /** Syntax highlighting styles. */\n styles: TagStyle[]\n}\n\ntype Theme = 'light' | 'dark'\n\nexport type Settings = {\n /** Editor background color. */\n background?: string\n /** Editor background image. */\n backgroundImage?: string\n /** Default text color. */\n foreground?: string\n /** Caret color. */\n caret?: string\n /** Selection background. */\n selection?: string\n /** Selection match background. */\n selectionMatch?: string\n /** Background of highlighted lines. */\n lineHighlight?: string\n /** Gutter background. */\n gutterBackground?: string\n /** Text color inside gutter. */\n gutterForeground?: string\n /** Text active color inside gutter. */\n gutterActiveForeground?: string\n /** Gutter right border color. */\n gutterBorder?: string\n /** set editor font */\n fontFamily?: string\n /** set editor font size */\n fontSize?: StyleSpec['fontSize']\n}\n\n/**\n * Creates a CodeMirror theme from a set of options.\n */\nexport const createCodeMirrorTheme = ({ theme, settings = {}, styles = [] }: CreateThemeOptions): Extension => {\n const themeOptions: Record<string, StyleSpec> = {\n '.cm-gutters': {},\n }\n const baseStyle: StyleSpec = {}\n if (settings.background) {\n baseStyle.backgroundColor = settings.background\n }\n if (settings.backgroundImage) {\n baseStyle.backgroundImage = settings.backgroundImage\n }\n if (settings.foreground) {\n baseStyle.color = settings.foreground\n }\n if (settings.fontSize) {\n baseStyle.fontSize = settings.fontSize\n }\n if (settings.background || settings.foreground) {\n themeOptions['&'] = baseStyle\n }\n\n if (settings.fontFamily) {\n themeOptions['&.cm-editor .cm-scroller'] = {\n fontFamily: settings.fontFamily,\n }\n }\n if (settings.gutterBackground) {\n themeOptions['.cm-gutters'].backgroundColor = settings.gutterBackground\n }\n if (settings.gutterForeground) {\n themeOptions['.cm-gutters'].color = settings.gutterForeground\n }\n if (settings.gutterBorder) {\n themeOptions['.cm-gutters'].borderRightColor = settings.gutterBorder\n }\n\n if (settings.caret) {\n themeOptions['.cm-content'] = {\n caretColor: settings.caret,\n }\n themeOptions['.cm-cursor, .cm-dropCursor'] = {\n borderLeftColor: settings.caret,\n }\n }\n const activeLineGutterStyle: StyleSpec = {}\n if (settings.gutterActiveForeground) {\n activeLineGutterStyle.color = settings.gutterActiveForeground\n }\n if (settings.lineHighlight) {\n themeOptions['.cm-activeLine'] = {\n backgroundColor: settings.lineHighlight,\n }\n activeLineGutterStyle.backgroundColor = settings.lineHighlight\n }\n themeOptions['.cm-activeLineGutter'] = activeLineGutterStyle\n\n if (settings.selection) {\n themeOptions[\n '&.cm-focused .cm-selectionBackground, & .cm-line::selection, & .cm-selectionLayer .cm-selectionBackground, .cm-content ::selection'\n ] = {\n background: settings.selection + ' !important',\n }\n }\n if (settings.selectionMatch) {\n themeOptions['& .cm-selectionMatch'] = {\n backgroundColor: settings.selectionMatch,\n }\n }\n const themeExtension = EditorView.theme(themeOptions, {\n dark: theme === 'dark',\n })\n\n const highlightStyle = HighlightStyle.define(styles)\n const extension = [themeExtension, syntaxHighlighting(highlightStyle)]\n\n return extension\n}\n"],
5
+ "mappings": "AAOA,SAAS,gBAA+B,0BAA0B;AAElE,SAAS,kBAAkB;AAkDpB,MAAM,wBAAwB,CAAC,EAAE,OAAO,WAAW,CAAC,GAAG,SAAS,CAAC,EAAE,MAAqC;AAC7G,QAAM,eAA0C;AAAA,IAC9C,eAAe,CAAC;AAAA,EAClB;AACA,QAAM,YAAuB,CAAC;AAC9B,MAAI,SAAS,YAAY;AACvB,cAAU,kBAAkB,SAAS;AAAA,EACvC;AACA,MAAI,SAAS,iBAAiB;AAC5B,cAAU,kBAAkB,SAAS;AAAA,EACvC;AACA,MAAI,SAAS,YAAY;AACvB,cAAU,QAAQ,SAAS;AAAA,EAC7B;AACA,MAAI,SAAS,UAAU;AACrB,cAAU,WAAW,SAAS;AAAA,EAChC;AACA,MAAI,SAAS,cAAc,SAAS,YAAY;AAC9C,iBAAa,GAAG,IAAI;AAAA,EACtB;AAEA,MAAI,SAAS,YAAY;AACvB,iBAAa,0BAA0B,IAAI;AAAA,MACzC,YAAY,SAAS;AAAA,IACvB;AAAA,EACF;AACA,MAAI,SAAS,kBAAkB;AAC7B,iBAAa,aAAa,EAAE,kBAAkB,SAAS;AAAA,EACzD;AACA,MAAI,SAAS,kBAAkB;AAC7B,iBAAa,aAAa,EAAE,QAAQ,SAAS;AAAA,EAC/C;AACA,MAAI,SAAS,cAAc;AACzB,iBAAa,aAAa,EAAE,mBAAmB,SAAS;AAAA,EAC1D;AAEA,MAAI,SAAS,OAAO;AAClB,iBAAa,aAAa,IAAI;AAAA,MAC5B,YAAY,SAAS;AAAA,IACvB;AACA,iBAAa,4BAA4B,IAAI;AAAA,MAC3C,iBAAiB,SAAS;AAAA,IAC5B;AAAA,EACF;AACA,QAAM,wBAAmC,CAAC;AAC1C,MAAI,SAAS,wBAAwB;AACnC,0BAAsB,QAAQ,SAAS;AAAA,EACzC;AACA,MAAI,SAAS,eAAe;AAC1B,iBAAa,gBAAgB,IAAI;AAAA,MAC/B,iBAAiB,SAAS;AAAA,IAC5B;AACA,0BAAsB,kBAAkB,SAAS;AAAA,EACnD;AACA,eAAa,sBAAsB,IAAI;AAEvC,MAAI,SAAS,WAAW;AACtB,iBACE,oIACF,IAAI;AAAA,MACF,YAAY,SAAS,YAAY;AAAA,IACnC;AAAA,EACF;AACA,MAAI,SAAS,gBAAgB;AAC3B,iBAAa,sBAAsB,IAAI;AAAA,MACrC,iBAAiB,SAAS;AAAA,IAC5B;AAAA,EACF;AACA,QAAM,iBAAiB,WAAW,MAAM,cAAc;AAAA,IACpD,MAAM,UAAU;AAAA,EAClB,CAAC;AAED,QAAM,iBAAiB,eAAe,OAAO,MAAM;AACnD,QAAM,YAAY,CAAC,gBAAgB,mBAAmB,cAAc,CAAC;AAErE,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createCodeMirrorTheme } from "./createCodeMirrorTheme.js";
3
+ describe("createCodeMirrorTheme", () => {
4
+ it("creates a theme", () => {
5
+ const theme = createCodeMirrorTheme({
6
+ theme: "light",
7
+ settings: {
8
+ background: "#ffffff",
9
+ foreground: "#000000",
10
+ caret: "#ff0000"
11
+ },
12
+ styles: []
13
+ });
14
+ expect(theme).toBeInstanceOf(Array);
15
+ expect(theme).toHaveLength(2);
16
+ });
17
+ });
18
+ //# sourceMappingURL=createCodeMirrorTheme.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/themes/createCodeMirrorTheme.test.ts"],
4
+ "sourcesContent": ["import { describe, expect, it } from 'vitest'\n\nimport { createCodeMirrorTheme } from './createCodeMirrorTheme'\n\ndescribe('createCodeMirrorTheme', () => {\n it('creates a theme', () => {\n const theme = createCodeMirrorTheme({\n theme: 'light',\n settings: {\n background: '#ffffff',\n foreground: '#000000',\n caret: '#ff0000',\n },\n styles: [],\n })\n\n expect(theme).toBeInstanceOf(Array)\n expect(theme).toHaveLength(2)\n })\n})\n"],
5
+ "mappings": "AAAA,SAAS,UAAU,QAAQ,UAAU;AAErC,SAAS,6BAA6B;AAEtC,SAAS,yBAAyB,MAAM;AACtC,KAAG,mBAAmB,MAAM;AAC1B,UAAM,QAAQ,sBAAsB;AAAA,MAClC,OAAO;AAAA,MACP,UAAU;AAAA,QACR,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,CAAC;AAAA,IACX,CAAC;AAED,WAAO,KAAK,EAAE,eAAe,KAAK;AAClC,WAAO,KAAK,EAAE,aAAa,CAAC;AAAA,EAC9B,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }