yikoyu / vuetify-pro-tiptap

A Rich Text Editor (WYSIWYG) for Vue3 with tiptap & Vuetify.
https://yikoyu.github.io/vuetify-pro-tiptap/
MIT License
159 stars 23 forks source link

Need Help: Making Specific Words in a sentence "Uneditable or Readonly" in Vuetify-Pro-Tiptap #254

Open ravi-cloudworks opened 8 months ago

ravi-cloudworks commented 8 months ago

Hello community, I'm new to Vuetify-Pro-Tiptap and currently exploring the use case of making specific document portions "uneditable or readonly" with Vuetify-Pro-Tiptap. Our goal is to restrict editing in specific words within a sentence while maintaining the overall functionality. Any insights on achieving this or guidance to relevant materials would be highly valuable. Thanks.

SergkeiM commented 4 months ago

Hi @ravi-cloudworks

You can check this guide https://tiptap.dev/docs/editor/guide/node-views/vue

You can create Custon nodes and set wich area should be Editable.

Example:

Section.js (Custom Node)

import { mergeAttributes, Node } from '@tiptap/core'
import { VueNodeViewRenderer } from '@tiptap/vue-3'

import SectionComponent from './components/Section.vue'
import SectionAction from './components/SectionAction.vue'

const Section = Node.create({
    name: 'section',
    group: 'section',
    content: 'block+',
    draggable: true,
    selectable: false,
    inline: false,
    priority: 1000,
    addCommands() {
        return {
            insertSection: () => ({ chain }) => {

                chain()
                .focus('end')
                .insertContent({
                    type: 'section',
                    content: [
                        {
                            type: "paragraph",
                            content: []
                        },
                    ],
                })
                .focus('end')
                .run()
            },
        };
    },
    addOptions() {
        return {
            ...this.parent?.(),
            button: ({ editor }) => ({
                component: SectionAction,
                componentProps: {
                    action: () => editor.commands.insertSection()
                }
            })
        }
    },
    parseHTML() {
        return [
            {
                tag: 'div[data-type="section"]',
            },
        ]
    },
    renderHTML({ HTMLAttributes }) {
        return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'section' }), 0]
    },
    addNodeView() {
        return VueNodeViewRenderer(SectionComponent)
    },
})

export default Section

SectionComponent

<template>
    <NodeViewWrapper>
        <VCard
            flat
            border="md"
            class="mb-2"
        >
            <VToolbar density="compact" flat height="auto" class="py-1 ps-1">
                <VBtn
                    class="rounded me-1 ms-0"
                    density="comfortable"
                    size="small"
                    icon
                    draggable="true"
                    contenteditable="false"
                    data-drag-handle
                >
                    <VIcon :icon="mdiDrag" />
                    <VTooltip :eager="false" activator="parent" location="top" text="Move section" />
                </VBtn>
                <VBtn
                    class="rounded me-1 ms-0"
                    density="comfortable"
                    size="small"
                    icon
                    @click="deleteNode"
                >
                    <VIcon :icon="mdiDelete" />
                    <VTooltip :eager="false" activator="parent" location="top" text="Delete section" />
                </VBtn>
            </VToolbar>
            <VCardText class="pa-4">
               <!-- Editable part -->
                <NodeViewContent
                    class="section-content"
                />
            </VCardText>
        </VCard>
    </NodeViewWrapper>
</template>
<script setup>
    import { mdiDrag, mdiDelete } from '@mdi/js';
    import { nodeViewProps, NodeViewWrapper, NodeViewContent } from '@tiptap/vue-3'

    defineProps(nodeViewProps)
</script>

SectionAction

<template>
    <VBtn
        class="rounded me-1 ms-0"
        density="comfortable"
        size="small"
        icon
        @click="action"
    >
        <VIcon :icon="mdiFormatListGroupPlus" />
        <VTooltip :eager="false" activator="parent" location="top" text="Insert Section" />
    </VBtn>
</template>
<script setup>
    import { mdiFormatListGroupPlus } from '@mdi/js';

    defineProps({
        action: {
            type: Function,
            required: true
        },
    })
</script>

Result

image