npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vuetify-pro-tiptap

v2.5.4

Published

tiptap text editor on vuejs and vuetify

Downloads

6,266

Readme

Vuetify Pro Tiptap

一个 Vue.js 的基于 tiptapvuetify 的 「所见即所得」 富文本编辑器

download version gzip Test LICENSE semantic-release: vue

English | 中文

Demo

👉https://yikoyu.github.io/vuetify-pro-tiptap/

👾Code Sandbox

👾Nuxt3 Code Sandbox

特色

  • 使用 vuetify 组件
  • 许多开箱即用的 extension (欢迎提交 issue 为新的 feature 留下建议)
  • 支持 markdown 语法
  • TypeScript 支持
  • 支持 i18n
  • Vuetify 3.x 和 Vue 3.x 支持

Vuetify 2.x

Vuetify 2.x 请使用最新版本的 [email protected]

安装

NPM安装

pnpm add vuetify-pro-tiptap
# 或者
yarn add vuetify-pro-tiptap
# 或者
npm i vuetify-pro-tiptap -S

安装插件

import { markRaw } from 'vue'
import { VuetifyTiptap, VuetifyViewer, createVuetifyProTipTap } from 'vuetify-pro-tiptap'
import { BaseKit, Bold, Italic, Underline, Strike, Color, Highlight, Heading, TextAlign, FontFamily, FontSize, SubAndSuperScript, BulletList, OrderedList, TaskList, Indent, Link, Image, Video, Table, Blockquote, HorizontalRule, Code, CodeBlock, Clear, Fullscreen, History } from 'vuetify-pro-tiptap'
import 'vuetify-pro-tiptap/style.css'
import SelectImage from './components/SelectImage.vue'

export const vuetifyProTipTap = createVuetifyProTipTap({
  lang: 'zhHans',
  components: {
    VuetifyTiptap,
    VuetifyViewer
  },
  extensions: [
    BaseKit.configure({
      placeholder: {
        placeholder: 'Enter some text...'
      }
    }),
    Bold,
    Italic,
    Underline,
    Strike,
    Code.configure({ divider: true }),
    Heading,
    TextAlign,
    FontFamily,
    FontSize,
    Color,
    Highlight.configure({ divider: true }),
    SubAndSuperScript.configure({ divider: true }),
    Clear.configure({ divider: true }),
    BulletList,
    OrderedList,
    TaskList,
    Indent.configure({ divider: true }),
    Link,
    Image.configure({
      imageTabs: [{ name: 'SELECT', component: markRaw(SelectImage) }],
      // hiddenTabs: ['upload'],
      upload(file: File) {
        const url = URL.createObjectURL(file)
        console.log('mock upload api :>> ', url)
        return Promise.resolve(url)
      }
    }),
    Video,
    Table.configure({ divider: true }),
    Blockquote,
    HorizontalRule,
    CodeBlock.configure({ divider: true }),
    History.configure({ divider: true }),
    Fullscreen
  ]
})
import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import 'vuetify/styles'
import App from './App.vue'

import { vuetifyProTipTap } from './tiptap'

const vuetify = createVuetify()

const app = createApp(App)
app.use(vuetify)
app.use(vuetifyProTipTap)

// fix warning injected property "decorationClasses" is a ref and will be auto-unwrapped
// https://github.com/ueberdosis/tiptap/issues/1719
app.config.unwrapInjectedRef = true

app.mount('#app')

全局设置

import { markRaw } from 'vue'
import { VuetifyTiptap, VuetifyViewer, createVuetifyProTipTap, defaultBubbleList } from 'vuetify-pro-tiptap'
import { BaseKit, Image, Fullscreen } from 'vuetify-pro-tiptap'
import 'vuetify-pro-tiptap/style.css'
import SelectImage from './components/SelectImage.vue'

export const vuetifyProTipTap = createVuetifyProTipTap({
  // Set default lang
  lang: 'zhHans',
  // Set markdown theme
  markdownTheme: 'github',
  // Global registration app.component
  components: {
    VuetifyTiptap,
    VuetifyViewer
  },
  // Global registration extensions
  extensions: [
    BaseKit.configure({
      placeholder: {
        placeholder: 'Enter some text...'
      },
      bubble: {
        // default config
        list: {
          image: [ 'float-left', 'float-none', 'float-right', 'divider', 'size-small', 'size-medium', 'size-large', 'divider', 'textAlign', 'divider', 'image', 'image-aspect-ratio', 'remove'],
          text: ['bold', 'italic', 'underline', 'strike', 'divider', 'color', 'highlight', 'textAlign', 'divider', 'link'],
          video: ['video', 'remove']
        },
        defaultBubbleList: editor => {
          // You can customize the bubble menu here
          return defaultBubbleList(editor) // default customize bubble list
        }
      }
    }),
    Image.configure({
      // Generate a VDivider after the button
      divider: true,
      // Custom image tabs
      imageTabs: [{ name: 'SELECT', component: markRaw(SelectImage) }],
      // hidden default tab
      hiddenTabs: ['upload'],
      // custom upload function
      upload(file) {
        const url = URL.createObjectURL(file)
        console.log('mock upload api :>> ', url)
        return Promise.resolve(url)
      }
    }),
    Fullscreen.configure({
      // Generate a VSpacer after the button
      spacer: true
    })
  ]
})

Extensions

你可以只使用需要的 extension,对应的菜单按钮将会按照你声明的顺序被添加。

所有可用的 extensions:

自定义主题

创建 github.scss

$value: 'github';

.vuetify-pro-tiptap-editor__content.markdown-theme-#{$value} {
  // 自定义样式
  &.__dark {
    // dark 模式下的自定义样式
  }
}

在 ts 中导入 github.scss

// import 'vuetify-pro-tiptap/style.css' // 导入全部(editor 和 markdown)样式
import 'vuetify-pro-tiptap/styles/editor.css' // 只使用 editor 样式,不使用 markdown 样式
import './styles/markdown/github.scss'

在组件中使用

<template>
  <VuetifyTiptap v-model="content" markdown-theme="github" />
  <VuetifyViewer :value="content" markdown-theme="github" />
</template>

自定义 extension

<script setup lang="ts">
import { ref } from 'vue'
import { mdiClose, mdiFileCodeOutline } from '@mdi/js'
import type { Editor } from '@tiptap/vue-3'
import { ActionButton } from 'vuetify-pro-tiptap'

interface Props {
  editor: Editor
  tooltip?: string
  disabled?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  tooltip: undefined,
  disabled: false
})

const dialog = ref(false)
const maxWidth = ref<number>(900)
</script>

<template>
  <ActionButton tooltip="全屏" :disabled="disabled">
    <VIcon>{{ `svg:${mdiFileCodeOutline}` }}</VIcon>
    <VDialog v-model="dialog" fullscreen hide-overlay activator="parent">
      <VCard>
        <VToolbar dark color="primary">
          <VBtn icon dark @click="dialog = false">
            <VIcon>{{ `svg:${mdiClose}` }}</VIcon>
          </VBtn>
        </VToolbar>

        <VContainer>
          <VSheet class="mx-auto" :max-width="maxWidth">
            <VuetifyViewer :value="editor.getHTML()" />
          </VSheet>
        </VContainer>
      </VCard>
    </VDialog>
  </ActionButton>
</template>
import { Extension } from '@tiptap/core'

import type { ButtonView, GeneralOptions } from 'vuetify-pro-tiptap'
import PreviewActionButton from '../components/PreviewActionButton.vue'

export interface PreviewOptions extends GeneralOptions {
  button: ButtonView
}

export default Extension.create<PreviewOptions>({
  name: 'preview',
  addOptions() {
    return {
      divider: false,
      spacer: false,
      button: () => ({
        component: PreviewActionButton,
        componentProps: {}
      })
    }
  }
})

国际化

设置语言

你可以在安装插件的时候声明

import { createVuetifyProTipTap } from 'vuetify-pro-tiptap'

const VuetifyProTipTap = createVuetifyProTipTap({
  lang: 'zhHans'
})

或者调用方法动态修改

import { locale } from 'vuetify-pro-tiptap'

locale.setLang('en')

可用的语言:

  • en (默认)
  • zhHans
  • nl
  • de

加载新语言

当前语言暂未提供时,可以使用 setMessage 进行设置

import { locale } from 'vuetify-pro-tiptap'

locale.setMessage('zhHant', {
  // 国际化文本
})
locale.setLang('zhHant')

用法

<script setup lang="ts">
import { ref } from 'vue'
import { BaseKit, Bold, Color, Fullscreen, Heading, Highlight, History, Image, Italic, Link, Strike, Table, Underline, Video, VuetifyTiptap, VuetifyViewer } from 'vuetify-pro-tiptap'
import 'vuetify-pro-tiptap/style.css'

const extensions = [
  BaseKit.configure({
    placeholder: {
      placeholder: 'Enter some text...'
    }
  }),
  Bold,
  Italic,
  Underline,
  Strike,
  Color,
  Highlight,
  Heading,
  Link,
  Image,
  Video,
  Table,
  Fullscreen,
  History
]

const content = ref('')
</script>

<template>
  <VApp id="app">
    <VContainer>
      <VuetifyTiptap v-model="content" label="Title" rounded :min-height="200" :max-height="465" :max-width="900" :extensions="extensions" />
      <VuetifyViewer :value="content" />
    </VContainer>
  </VApp>
</template>

Props

VuetifyTiptap

Props

| 名称 | 类型 | 默认值 | 说明 | | -------------------- | ------------------------------------------ | --------- | ---------------------------- | | modelValue | string | '' | 输入的值 | | markdownTheme | string | false | 'default' | markdown主题 | | output | 'html' | 'json' | 'text' | 'html' | 输出格式 | | dark | boolean | false | 是否为深色主题 | | dense | boolean | false | 是否为紧凑模式 | | outlined | boolean | true | 将轮廓样式应用于输入 | | flat | boolean | true | 移除卡片的 elevation | | disabled | boolean | false | 禁用输入 | | label | string | undefined | 设置输入标签 | | hideToolbar | boolean | false | 隐藏工具栏 | | disableToolbar | boolean | false | 禁用工具栏 | | hideBubble | boolean | false | 隐藏气泡菜单 | | removeDefaultWrapper | boolean | false | 删除编辑器为空时默认的包装器 | | maxWidth | string | number | undefined | 输入框最大宽度 | | minHeight | string | number | undefined | 输入框最小高度 | | maxHeight | string | number | undefined | 输入框最大高度 | | extensions | AnyExtension[] | [] | tiptap插件 | | editorClass | string | string[] | Record<string, any> | undefined | 编辑器class |

Slots

| 名称 | 说明 | | ------ | ---------------------- | | editor | 自定义编辑器的插槽 | | bottom | 自定义编辑器底部的插槽 |

Event

| 名称 | 类型 | 说明 | | -------------------- | ------------------------------------------------- | ------------------------ | | update:modelValue | string | JSONContent | 编辑器 onUpdate 时处触发 | | update:markdownTheme | string | 切换主题时触发 | | change | { editor: Editor, output: string | JSONContent } | 编辑器 onUpdate 时处触发 | | enter | | 键盘输入回车时触发 |

VuetifyViewer

Props

| 名称 | 类型 | 默认值 | 说明 | | ------------- | --------------------- | ------------ | --------------- | | value | string | JSONContent | '' | 预览的值 | | dark | boolean | false | 是否为深色主题 | | dense | boolean | false | 是否为紧凑模式 | | markdownTheme | string | false | 'default' | markdown主题 | | xss | boolean | true | 是否开启xss过滤 | | xssOptions | xss.IWhiteList | 内置默认规则 | xss过滤规则配置 | | maxWidth | string | number | undefined | 预览最大宽度 | | extensions | AnyExtension[] | [] | tiptap插件 |

Slots

| 名称 | 说明 | | ------ | -------------- | | before | 在顶部添加内容 | | after | 在底部添加内容 |

🏗 贡献代码

  1. 🍴Fork it
  2. 🔀Create your branch: git checkout -b your-branch
  3. 🎨Make your changes
  4. 📝Commit your changes with Semantic Commit Messages (recommended)
  5. 🚀Push to the branch: git push origin your-branch
  6. 🎉Submit a PR to master branch

📄 许可证

MIT

🌹 鸣谢