jaredreich/pell

DOC: Vue3.2 composition example + suggestion

Opened this issue · 1 comments

hi, LOVE the size of this library.

first lets get the suggestion out of the way. since the library has an init wont it make sense to have an "update" method as well? basicaly a wrapper for instance.content.innerHTML = 'new value' just to keep consitent?


for vue3.2 im using this and it seems to work ok

EditorComponent.vue

<template>
    <div ref="editor"></div>
</template>
<script setup>
import {
    ref,
    computed,
    reactive,
    onMounted,
    watch
} from "vue";
import pell from 'pell'

const props = defineProps(["modelValue"]);
const emits = defineEmits(["update:modelValue"]);
const editor = ref(null);
let last_value = null;

const content = computed({
    get(){
        return props.modelValue
    },
    set(value){
        // we emit the value back up to the parent component
        emits("update:modelValue",value);
        // need to know when to fire off thew watcher. dont want it updating the content with every char typed
        last_value = value
    }
})

onMounted(()=>{
    editor.value = pell.init({
      element: editor.value,
      onChange: html => {
          content.value = html
      },
      actions: [
        'bold',
        'italic',
        'underline',
        'strikethrough',
        'heading1',
        'heading2',
        'paragraph',
        'quote',
        'olist',
        'ulist',
        'code',
        'line',
      ]
    })
   // setting the initial values. not sure if they both needed but here goes
    editor.value.content.innerHTML = content.value
    last_value = content.value
})

watch(content,(to)=>{
    // while typing we dont want the watcher to keep updating the value since that keep jumping our cursor to the begining
    if (to != last_value){
        editor.value.content.innerHTML = to
    }
})
</script>

and usage

<template>
    <EditorComponent v-model="content"></EditorComponent>

    <div>
        <!-- the value of the editor is reactive -->
        <pre>
            {{ content }}
         </pre>
         <!-- We can then update the contents from here-->
         <button @click="content = `<div><strong>strong</strong> <em>em</em> <p>para</p> <hr></div>`">set value</button>
    </div>
</template>

<script setup>
import EditorComponent from "@/components/form/EditorComponent.vue";
import {
    ref,
} from "vue";
const content = ref(`<b>initial content</b>`);
</script>

New version time, This brings in being able to add a class / style dynamically to the content area (min-height etc)

EditorComponent.vue

<template>
    <div ref="editor" class="editor-area"></div>
</template>
<script setup>
import {
    ref,
    computed,
    reactive,
    onMounted,
    watch
} from "vue";
import pell from "pell";

const props = defineProps([
    "modelValue",
    "style",
    "class"
]);
const emits = defineEmits(["update:modelValue"]);
const editor = ref(null);
let last_value = null;
const content = computed({
    get() {
        return props.modelValue;
    },
    set(value) {
        emits("update:modelValue", value);
        last_value = value;
    }
});

const classes = {
    actionbar: "editor-nav",
    button: "editor-btn btn",
    content: "editor-content form-control",
    selected: "editor-btn-selected"
};

onMounted(() => {
    editor.value = pell.init({
        element: editor.value,
        onChange: html => {
            content.value = html;
        },
        actions: [
            "bold",
            "italic",
            "underline",
            "strikethrough",
            // "heading1",
            // "heading2",
            // "paragraph",
            // "quote",
            "olist",
            "ulist",
            // "code",
            "line",
        ],
        classes: Object.assign({}, classes, {content: classes.content + " " + props.class})
    });
    editor.value.content.innerHTML = content.value;
    last_value = content.value;

});

watch(content, (to) => {
    if (to != last_value) {
        editor.value.content.innerHTML = to;
    }
});


const styles = ref(props.style);
const watch_classes = computed(() => props.class);
watch(watch_classes, (to) => {
    editor.value.getElementsByClassName("editor-content")[0].className = classes.content + " " + to;
});
const watch_styles = computed(() => props.style);
watch(watch_styles, (to) => {
    editor.value.getElementsByClassName("editor-content")[0].style.cssText = to;
});

</script>

usage

<EditorComponent v-model="content"  :class="classes" :style="styles"></EditorComponent>

<button @click.prevent="classes = `bg-warning`">Set class .bg-warning</button>
<button @click.prevent="classes = `bg-danger`">Set class .bg-danger</button>
<button @click.prevent="styles = `min-height:600px;`">Set style min-height to 600</button>
 <button @click.prevent="styles = `min-height:300px; background:purple;`">Set style min-height to 300 and background to purple</button>
<button @click.prevent="styles=null; classes=null">Reset </button>

...

const classes = ref(null);
const styles = ref(null);