DEV Community

medilies
medilies

Posted on

CodeMirror v6 on Vue3 hooked to Pinia store

Scope

I'm gonna make a very basic Codepen clone for writing HTML and CSS, and integrate CodeMirror in Vue using vue-codemirror wrapper.

Setup

After setting up Vue with Pinia, install the following packages:

 npm i vue-codemirror @codemirror/lang-css @codemirror/lang-html @codemirror/theme-one-dark 
Enter fullscreen mode Exit fullscreen mode

Code

1. The store

 import { defineStore } from "pinia"; import { computed, ref } from "vue"; export const useAppStore = defineStore("app", () => { const css = ref(""); const cssCopy = computed(() => css.value); const setCss = (newCss) => { css.value = newCss; }; const template = ref(""); const templateCopy = computed(() => template.value); const setTemplate = (newTemplate) => { template.value = newTemplate; }; return { css, cssCopy, setCss, template, templateCopy, setTemplate, }; }); 
Enter fullscreen mode Exit fullscreen mode

This is the store I made to keep track of the value of HTML and CSS code.

2. Base text editor component

 <template> <codemirror :modelValue="props.code" placeholder="code goes here..." :style="{ height: '100%' }" :autofocus="true" :indent-with-tab="true" :tab-size="4" :extensions="extensions" @ready="handleReady" /> </template> <script setup> import { shallowRef, computed } from "vue"; import { Codemirror } from "vue-codemirror"; import { oneDark } from "@codemirror/theme-one-dark"; const props = defineProps({ additionalExtensions: { type: Array, required: true, default: [], }, code: { type: String, required: true, }, }); const baseExtensions = [oneDark]; const extensions = computed(() => [ ...baseExtensions, ...props.additionalExtensions, ]); const view = shallowRef(); const handleReady = (payload) => { view.value = payload.view; }; </script> 
Enter fullscreen mode Exit fullscreen mode

This component defines two simple properties:

  1. additionalExtensions mainly to add language support.
  2. code to access value from store.

3. Language specific text editors

 

<template>
<base-editor
:additional-extensions="[html()]"
:code="store.templateCopy"
@change="store.setTemplate($event)"
/>
</template>

<script setup>
import { html } from "@codemirror/lang-html";

import { useAppStore } from "@/stores/app";
import BaseEditor from "@/components/BaseEditor.vue";

const store = useAppStore();

store.setTemplate("<h1>template</h1>");
</script>

Enter fullscreen mode Exit fullscreen mode
 

<template>
<base-editor
:additionalExtensions="[css()]"
:code="store.cssCopy"
@change="store.setCss($event)"
/>
</template>

<script setup>
import { css } from "@codemirror/lang-css";

import { useAppStore } from "@/stores/app";
import BaseEditor from "@/components/BaseEditor.vue";

const store = useAppStore();

store.setCss(* {
padding = 0;
margin = 0;
}
);
</script>

Enter fullscreen mode Exit fullscreen mode



  1. Putting It All Together

 

<template>
<div class="grid h-screen grid-cols-8 overflow-hidden bg-slate-800">
<div class="h-screen col-span-4 overflow-hidden border border-gray-300">
<div v-html="compiledCode"></div>
</div>
<div
class="flex flex-col col-span-4 overflow-hidden border border-gray-300 grow-0 shrink basis-full"
>
<div
class="overflow-hidden border border-gray-300 grow-0 shrink basis-1/2"
>
<div class="h-full overflow-auto">
<HtmlEditor />
</div>
</div>
<div
class="overflow-hidden border border-gray-300 grow-0 shrink basis-1/2"
>
<div class="h-full overflow-auto">
<CssEditor />
</div>
</div>
</div>
</div>
</template>

<script setup>
import { computed } from "vue";
import HtmlEditor from "@/components/HtmlEditor.vue";
import CssEditor from "@/components/CssEditor.vue";

import { useAppStore } from "@/stores/app";

const store = useAppStore();

const compiledCode = computed(() => {
return
&lt;style&gt;</span><span class="p">${</span><span class="nx">store</span><span class="p">.</span><span class="nx">css</span><span class="p">}</span><span class="s2">&lt;/style&gt;
</span><span class="p">${</span><span class="nx">store</span><span class="p">.</span><span class="nx">template</span><span class="p">}</span><span class="s2">
;
});
</script>

Enter fullscreen mode Exit fullscreen mode




Results

screenshot

Top comments (0)