vue2-premium-bbl-editor
v1.3.0
Published
A production-ready, fully configurable rich text editor for Vue 2.6 built with Tiptap
Downloads
39
Maintainers
Readme
Vue 2 Premium BBL Editor
A production-ready, fully configurable rich text editor for Vue 2.6 applications. Built with Tiptap and designed for professional use with extensive customization options and advanced upload management system.
🚀 Features
- ✅ Vue 2.6 Compatible - Full support for Vue 2.6+ applications
- ✅ Production Ready - Thoroughly tested and optimized for production use
- ✅ Fully Configurable - Extensive props for customizing every aspect
- ✅ Rich Text Editing - Complete formatting options (bold, italic, underline, etc.)
- ✅ Advanced Media - Resizable images and videos with upload support
- ✅ Smart Tables - Interactive tables with cell controls and resizing
- ✅ Upload Management - Comprehensive upload system with multiple adapters
- ✅ Multiple Themes - Default, minimal, and dark themes included
- ✅ TypeScript Support - Full TypeScript definitions included
- ✅ Accessibility - WCAG compliant with keyboard navigation
- ✅ Auto-save - Built-in auto-save functionality
- ✅ Source Code View - Toggle between visual and HTML source editing
- ✅ External Integration - Easy integration with existing projects
📦 Installation
npm install vue2-premium-bbl-editorPREVIEW
🎯 Quick Start
Global Registration (Recommended)
import Vue from 'vue'
import PremiumBblEditor from 'vue2-premium-bbl-editor'
// Register globally
Vue.use(PremiumBblEditor)
// Or register with options
Vue.use(PremiumBblEditor, {
registerAllComponents: true // Registers all sub-components globally
})Component Registration
// Composition API version (requires @vue/composition-api)
import { PremiumBblEditor } from 'vue2-premium-bbl-editor'
// Options API version (pure Vue 2)
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditor,
// or
PremiumBblEditorOptionsAPI
}
}Basic Usage
Composition API Version
<template>
<div>
<PremiumBblEditor
v-model="content"
placeholder="Start writing your content..."
@input="handleInput"
@ready="handleReady"
/>
</div>
</template>
<script>
export default {
data() {
return {
content: '<p>Hello World!</p>'
}
},
methods: {
handleInput(content) {
console.log('Content updated:', content)
},
handleReady(editor) {
console.log('Editor is ready:', editor)
}
}
}
</script>Options API Version
<template>
<div>
<PremiumBblEditorOptionsAPI
v-model="content"
placeholder="Start writing your content..."
@input="handleInput"
@ready="handleReady"
/>
</div>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>Hello World with Options API!</p>'
}
},
methods: {
handleInput(content) {
console.log('Content updated:', content)
},
handleReady(editor) {
console.log('Options API Editor is ready:', editor)
}
}
}
</script>📋 Complete Component API
Props
Content & Basic Configuration
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | String | '' | Editor content (v-model) |
| placeholder | String | 'Start writing...' | Placeholder text when editor is empty |
| editable | Boolean | true | Whether editor content can be modified |
| outputFormat | String | 'html' | Output format: 'html' or 'json' |
| autofocus | Boolean | false | Auto-focus editor on mount |
| spellcheck | Boolean | true | Enable browser spellcheck |
Layout & Appearance
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| maxHeight | String/Number | null | Maximum editor height (px or CSS value) |
| minHeight | String/Number | 200 | Minimum editor height (px or CSS value) |
| theme | String | 'default' | Theme: 'default', 'minimal', 'dark' |
| editorClass | String/Array/Object | '' | Custom CSS classes for editor container |
| toolbarClass | String/Array/Object | '' | Custom CSS classes for toolbar |
| contentClass | String/Array/Object | '' | Custom CSS classes for content area |
UI Component Visibility
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| showToolbar | Boolean | true | Show/hide main toolbar |
| showBubbleMenu | Boolean | true | Show/hide text selection bubble menu |
| showTableBubbleMenu | Boolean | true | Show/hide table-specific bubble menu |
| showImageBubbleMenu | Boolean | true | Show/hide image-specific bubble menu |
| showVideoBubbleMenu | Boolean | true | Show/hide video-specific bubble menu |
Toolbar Configuration
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| toolbarConfig | Object | See below | Configure which toolbar buttons to show |
Default Toolbar Configuration:
{
// Text formatting
bold: true,
italic: true,
underline: true,
strike: true,
code: true,
// Text styling
textColor: true,
highlight: true,
fontFamily: true,
fontSize: true,
// Alignment and spacing
textAlign: true,
lineHeight: true,
// Structure
headings: true,
lists: true,
blockquote: true,
codeBlock: true,
horizontalRule: true,
// Media
link: true,
image: true,
video: true,
table: true,
// Utilities
clearFormatting: true,
sourceCode: true,
undo: true,
redo: true
}Extension Configuration
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| extensionConfig | Object | See below | Configure extension behavior |
Default Extension Configuration:
{
image: {
allowResize: true,
allowAlignment: true,
allowDelete: true,
maxWidth: '100%',
quality: 0.8
},
video: {
allowResize: true,
allowAlignment: true,
allowDelete: true,
maxWidth: '100%',
autoplay: false
},
table: {
resizable: true,
allowRowControls: true,
allowColumnControls: true,
cellSelection: true
},
link: {
openOnClick: false,
autolink: true,
linkOnPaste: true
},
textAlign: {
types: ['heading', 'paragraph']
}
}Upload & Media Handling
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| uploadHandler | Function | null | Custom upload handler function |
| imageUploadUrl | String | null | URL endpoint for image uploads |
| videoUploadUrl | String | null | URL endpoint for video uploads |
| maxFileSize | Number | 10485760 | Maximum file size in bytes (10MB) |
| allowedImageTypes | Array | ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] | Allowed image MIME types |
| allowedVideoTypes | Array | ['video/mp4', 'video/webm', 'video/ogg'] | Allowed video MIME types |
Local File Base64 Management
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| useBase64Upload | Boolean | false | Force base64 conversion even when upload URLs are provided |
| base64Quality | Number | 0.8 | Image compression quality (0.1 - 1.0) |
| base64MaxWidth | Number | 1920 | Maximum width for compressed images (px) |
| base64MaxHeight | Number | 1080 | Maximum height for compressed images (px) |
| enableImageCompression | Boolean | true | Enable automatic image compression |
| preserveOriginalFileName | Boolean | true | Preserve original file names in alt text |
| base64Prefix | String | 'data:' | Custom prefix for base64 data URLs |
Content Restrictions
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| maxContentLength | Number | null | Maximum content length in characters |
| allowedHeadings | Array | [1, 2, 3, 4, 5, 6] | Allowed heading levels |
Styling Options
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| fontFamilies | Array | See below | Available font families |
| fontSizes | Array | See below | Available font sizes |
| lineHeights | Array | See below | Available line heights |
Default Font Options:
// Font Families
['Inter', 'Arial', 'Helvetica', 'Times New Roman', 'Georgia', 'Courier New', 'Monaco', 'Menlo']
// Font Sizes
['12px', '14px', '16px', '18px', '20px', '24px', '28px', '32px', '36px', '48px']
// Line Heights
['1', '1.2', '1.4', '1.6', '1.8', '2', '2.5', '3']Auto-save Configuration
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| autoSave | Boolean | false | Enable automatic content saving |
| autoSaveInterval | Number | 30000 | Auto-save interval in milliseconds |
Events
| Event | Payload | Description |
|-------|---------|-------------|
| input | content: string | Emitted when content changes (v-model) |
| update | content: string | Emitted when content updates |
| ready | editor: Editor | Emitted when editor is ready for use |
| created | editor: Editor | Emitted when editor instance is created |
| focus | - | Emitted when editor gains focus |
| blur | - | Emitted when editor loses focus |
| destroyed | - | Emitted when editor is destroyed |
| auto-save | content: string | Emitted during auto-save |
| content-limit-exceeded | {current: number, max: number} | Emitted when content exceeds limit |
| image-compressed | {originalSize: number, compressedSize: number, originalDimensions: object, compressedDimensions: object, compressionRatio: number} | Emitted when image is compressed |
| error | {type: string, message: string, ...} | Emitted when errors occur |
Methods
Access editor methods via template ref:
<template>
<PremiumBblEditor
ref="editor"
v-model="content"
/>
</template>
<script>
export default {
methods: {
focusEditor() {
this.$refs.editor.focus()
},
getContent() {
return this.$refs.editor.getContent()
},
setContent(content) {
this.$refs.editor.setContent(content)
},
executeCommand(command, options) {
this.$refs.editor.executeCommand(command, options)
}
}
}
</script>Available Methods:
focus()- Focus the editorblur()- Blur the editorgetContent(format?)- Get editor content ('html' or 'json')setContent(content, emitUpdate?)- Set editor contentexecuteCommand(command, options?)- Execute editor command
💡 Usage Examples
1. Basic Editor
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
placeholder="Start writing..."
@input="handleInput"
@ready="handleReady"
/>
</template>
<script>
export default {
data() {
return {
content: '<p>Hello World!</p>'
}
},
methods: {
handleInput(content) {
console.log('Content updated:', content)
},
handleReady(editor) {
console.log('Editor is ready:', editor)
}
}
}
</script>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
placeholder="Start writing..."
@input="handleInput"
@ready="handleReady"
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>Hello World with Options API!</p>'
}
},
methods: {
handleInput(content) {
console.log('Content updated:', content)
},
handleReady(editor) {
console.log('Options API Editor is ready:', editor)
}
}
}
</script>2. Minimal Configuration
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
theme="minimal"
:toolbar-config="{
bold: true,
italic: true,
underline: true,
link: true,
lists: true,
undo: true,
redo: true
}"
placeholder="Minimal editor..."
/>
</template>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
theme="minimal"
:toolbar-config="minimalToolbarConfig"
placeholder="Minimal editor with Options API..."
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>This is a minimal editor with limited features.</p>',
minimalToolbarConfig: {
bold: true,
italic: true,
underline: true,
link: true,
lists: true,
undo: true,
redo: true
}
}
}
}
</script>3. Advanced Configuration with Upload
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
:max-height="400"
:auto-save="true"
:auto-save-interval="15000"
:upload-handler="customUploadHandler"
:font-families="['Inter', 'Arial', 'Georgia']"
:extension-config="{
image: {
allowResize: true,
maxWidth: '800px'
},
table: {
resizable: true,
cellSelection: true
}
}"
@auto-save="handleAutoSave"
@ready="handleReady"
/>
</template>
<script>
export default {
data() {
return {
content: '<h2>Advanced Editor</h2><p>With custom upload handling...</p>'
}
},
methods: {
async customUploadHandler(file) {
const formData = new FormData()
formData.append('file', file)
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
})
const data = await response.json()
return { src: data.url, alt: file.name }
},
handleAutoSave(content) {
// Save to your backend
this.saveToServer(content)
},
handleReady(editor) {
console.log('Editor ready with advanced features')
}
}
}
</script>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
:max-height="maxHeight"
:auto-save="autoSave"
:auto-save-interval="autoSaveInterval"
:upload-handler="customUploadHandler"
:font-families="fontFamilies"
:extension-config="extensionConfig"
@auto-save="handleAutoSave"
@ready="handleReady"
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<h2>Advanced Options API Editor</h2><p>With comprehensive configuration...</p>',
maxHeight: 400,
autoSave: true,
autoSaveInterval: 15000,
fontFamilies: ['Inter', 'Arial', 'Georgia'],
extensionConfig: {
image: {
allowResize: true,
maxWidth: '800px',
quality: 0.9
},
table: {
resizable: true,
cellSelection: true,
allowRowControls: true
},
link: {
autolink: true,
linkOnPaste: true
}
}
}
},
methods: {
async customUploadHandler(file) {
try {
const formData = new FormData()
formData.append('file', file)
const response = await fetch('/api/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.getAuthToken()}`
},
body: formData
})
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`)
}
const data = await response.json()
return {
src: data.url,
alt: file.name,
width: data.width,
height: data.height
}
} catch (error) {
console.error('Upload error:', error)
throw error
}
},
handleAutoSave(content) {
console.log('Auto-saving content...')
this.saveToServer(content)
},
handleReady(editor) {
console.log('Options API Editor ready with advanced features')
// Store editor reference for later use
this.editor = editor
},
async saveToServer(content) {
try {
await fetch('/api/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.getAuthToken()}`
},
body: JSON.stringify({ content })
})
console.log('Content saved successfully')
} catch (error) {
console.error('Save failed:', error)
}
},
getAuthToken() {
return localStorage.getItem('authToken') || ''
}
}
}
</script>4. Read-only Display
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
:editable="false"
:show-toolbar="false"
:show-bubble-menu="false"
/>
</template>
<script>
export default {
data() {
return {
content: `
<h3>Read-only Content</h3>
<p>This content is displayed in <strong>read-only mode</strong>.</p>
<blockquote>
<p>Perfect for displaying formatted content without editing capabilities.</p>
</blockquote>
`
}
}
}
</script>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
:editable="editable"
:show-toolbar="showToolbar"
:show-bubble-menu="showBubbleMenu"
:show-table-bubble-menu="showTableBubbleMenu"
:show-image-bubble-menu="showImageBubbleMenu"
:show-video-bubble-menu="showVideoBubbleMenu"
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: `
<h3>Read-only Content (Options API)</h3>
<p>This content is displayed in <strong>read-only mode</strong> using Options API.</p>
<blockquote>
<p>Perfect for displaying formatted content without editing capabilities.</p>
</blockquote>
<ul>
<li>No toolbar visible</li>
<li>No bubble menus</li>
<li>Content cannot be modified</li>
</ul>
`,
editable: false,
showToolbar: false,
showBubbleMenu: false,
showTableBubbleMenu: false,
showImageBubbleMenu: false,
showVideoBubbleMenu: false
}
}
}
</script>5. Custom Styling & Dark Theme
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
theme="dark"
editor-class="custom-editor"
toolbar-class="custom-toolbar"
content-class="custom-content"
placeholder="Dark themed editor..."
/>
</template>
<style>
.custom-editor {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.custom-toolbar {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.custom-content {
font-family: 'Georgia', serif;
}
</style>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
:theme="theme"
:editor-class="editorClass"
:toolbar-class="toolbarClass"
:content-class="contentClass"
:placeholder="placeholder"
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>This Options API editor uses custom styling and dark theme.</p>',
theme: 'dark',
placeholder: 'Dark themed Options API editor...',
editorClass: 'custom-editor-options',
toolbarClass: 'custom-toolbar-options',
contentClass: 'custom-content-options'
}
}
}
</script>
<style scoped>
.custom-editor-options {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border: 2px solid #4f46e5;
}
.custom-toolbar-options {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-bottom: 1px solid #4f46e5;
}
.custom-content-options {
font-family: 'Georgia', serif;
line-height: 1.8;
}
</style>6. Local Base64 File Management
Composition API Version
<template>
<PremiumBblEditor
v-model="content"
:use-base64-upload="true"
:enable-image-compression="true"
:base64-quality="0.8"
:base64-max-width="1920"
:base64-max-height="1080"
:preserve-original-file-name="true"
placeholder="Upload images for local base64 conversion..."
@image-compressed="handleImageCompressed"
@ready="handleReady"
/>
</template>
<script>
export default {
data() {
return {
content: '<p>Upload images to see base64 conversion with compression!</p>'
}
},
methods: {
handleImageCompressed(compressionData) {
console.log('Image compressed:', {
originalSize: compressionData.originalSize,
compressedSize: compressionData.compressedSize,
compressionRatio: compressionData.compressionRatio,
savings: Math.round(((compressionData.originalSize - compressionData.compressedSize) / compressionData.originalSize) * 100) + '%'
})
},
handleReady(editor) {
console.log('Editor ready with base64 management')
}
}
}
</script>Options API Version
<template>
<PremiumBblEditorOptionsAPI
v-model="content"
:use-base64-upload="useBase64"
:enable-image-compression="enableCompression"
:base64-quality="quality"
:base64-max-width="maxWidth"
:base64-max-height="maxHeight"
:preserve-original-file-name="preserveNames"
placeholder="Options API with base64 management..."
@image-compressed="onImageCompressed"
@ready="onEditorReady"
/>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>Options API editor with base64 file management!</p>',
useBase64: true,
enableCompression: true,
quality: 0.8,
maxWidth: 1920,
maxHeight: 1080,
preserveNames: true
}
},
methods: {
onImageCompressed(data) {
console.log('Options API - Image compressed:', data)
// Show compression statistics
this.showCompressionStats(data)
},
onEditorReady(editor) {
console.log('Options API Editor ready with base64 management')
this.editorInstance = editor
},
showCompressionStats(data) {
const savings = Math.round(((data.originalSize - data.compressedSize) / data.originalSize) * 100)
alert(`Image compressed successfully!\nOriginal: ${this.formatFileSize(data.originalSize)}\nCompressed: ${this.formatFileSize(data.compressedSize)}\nSavings: ${savings}%`)
},
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
}
}
</script>7. Event Handling & Method Access
Composition API Version
<template>
<div>
<PremiumBblEditor
ref="editor"
v-model="content"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
@ready="handleReady"
@auto-save="handleAutoSave"
@content-limit-exceeded="handleLimitExceeded"
/>
<div class="editor-controls">
<button @click="focusEditor">Focus Editor</button>
<button @click="getEditorContent">Get Content</button>
<button @click="setEditorContent">Set Content</button>
<button @click="executeCustomCommand">Bold Text</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
content: '<p>Editor with comprehensive event handling...</p>'
}
},
methods: {
handleInput(content) {
console.log('Content changed:', content.length, 'characters')
},
handleFocus() {
console.log('Editor focused')
},
handleBlur() {
console.log('Editor blurred')
},
handleReady(editor) {
console.log('Editor ready:', editor)
},
handleAutoSave(content) {
console.log('Auto-saving content...')
// Save to backend
},
handleLimitExceeded({ current, max }) {
alert(`Content limit exceeded: ${current}/${max} characters`)
},
// Method examples
focusEditor() {
this.$refs.editor.focus()
},
getEditorContent() {
const content = this.$refs.editor.getContent()
console.log('Current content:', content)
},
setEditorContent() {
this.$refs.editor.setContent('<p>New content set programmatically!</p>')
},
executeCustomCommand() {
this.$refs.editor.executeCommand('toggleBold')
}
}
}
</script>Options API Version
<template>
<div>
<PremiumBblEditorOptionsAPI
ref="editorOptionsAPI"
v-model="content"
:max-content-length="maxContentLength"
:auto-save="autoSave"
:auto-save-interval="autoSaveInterval"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
@ready="handleReady"
@auto-save="handleAutoSave"
@content-limit-exceeded="handleLimitExceeded"
@error="handleError"
/>
<div class="editor-controls">
<button @click="focusEditor">Focus Editor</button>
<button @click="blurEditor">Blur Editor</button>
<button @click="getEditorContent">Get Content</button>
<button @click="setEditorContent">Set Content</button>
<button @click="executeCustomCommand">Toggle Bold</button>
<button @click="checkActiveState">Check Bold State</button>
<button @click="clearContent">Clear Content</button>
</div>
<div class="editor-status" v-if="editorStatus">
<h4>Editor Status</h4>
<p>Content Length: {{ contentLength }}</p>
<p>Is Bold Active: {{ isBoldActive }}</p>
<p>Last Action: {{ lastAction }}</p>
</div>
</div>
</template>
<script>
import { PremiumBblEditorOptionsAPI } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditorOptionsAPI
},
data() {
return {
content: '<p>Options API Editor with comprehensive event handling and method access...</p>',
maxContentLength: 5000,
autoSave: true,
autoSaveInterval: 20000,
editorInstance: null,
editorStatus: true,
contentLength: 0,
isBoldActive: false,
lastAction: 'None'
}
},
methods: {
handleInput(content) {
this.contentLength = content.length
this.lastAction = 'Content changed'
console.log('Options API - Content changed:', content.length, 'characters')
},
handleFocus() {
this.lastAction = 'Editor focused'
console.log('Options API - Editor focused')
},
handleBlur() {
this.lastAction = 'Editor blurred'
console.log('Options API - Editor blurred')
},
handleReady(editor) {
this.editorInstance = editor
this.lastAction = 'Editor ready'
console.log('Options API - Editor ready:', editor)
},
handleAutoSave(content) {
this.lastAction = 'Auto-saved'
console.log('Options API - Auto-saving content...')
this.saveToServer(content)
},
handleLimitExceeded({ current, max }) {
this.lastAction = `Content limit exceeded: ${current}/${max}`
alert(`Content limit exceeded: ${current}/${max} characters`)
},
handleError(error) {
this.lastAction = `Error: ${error.type}`
console.error('Options API - Editor error:', error)
},
// Method examples using the Options API component
focusEditor() {
this.$refs.editorOptionsAPI.focus()
this.lastAction = 'Focus method called'
},
blurEditor() {
this.$refs.editorOptionsAPI.blur()
this.lastAction = 'Blur method called'
},
getEditorContent() {
const htmlContent = this.$refs.editorOptionsAPI.getContent('html')
const jsonContent = this.$refs.editorOptionsAPI.getContent('json')
console.log('HTML Content:', htmlContent)
console.log('JSON Content:', jsonContent)
this.lastAction = 'Get content method called'
},
setEditorContent() {
const newContent = `
<h3>New Content Set Programmatically</h3>
<p>This content was set using the <strong>setContent</strong> method in Options API.</p>
<ul>
<li>Method called at: ${new Date().toLocaleTimeString()}</li>
<li>Using Options API component</li>
</ul>
`
this.$refs.editorOptionsAPI.setContent(newContent)
this.lastAction = 'Set content method called'
},
executeCustomCommand() {
this.$refs.editorOptionsAPI.executeCommand('toggleBold')
this.checkActiveState()
this.lastAction = 'Toggle bold command executed'
},
checkActiveState() {
this.isBoldActive = this.$refs.editorOptionsAPI.isActive('bold')
this.lastAction = 'Checked bold active state'
},
clearContent() {
this.$refs.editorOptionsAPI.setContent('<p></p>')
this.lastAction = 'Content cleared'
},
async saveToServer(content) {
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000))
console.log('Options API - Content saved to server')
} catch (error) {
console.error('Options API - Save failed:', error)
}
}
}
}
</script>
<style scoped>
.editor-controls {
margin: 20px 0;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.editor-controls button {
padding: 8px 16px;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.editor-controls button:hover {
background: #2563eb;
}
.editor-status {
margin-top: 20px;
padding: 15px;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 6px;
}
.editor-status h4 {
margin-top: 0;
color: #495057;
}
.editor-status p {
margin: 5px 0;
font-size: 14px;
color: #6c757d;
}
</style>🔌 Upload System Integration
The editor includes a comprehensive upload management system for handling file uploads with multiple adapters.
Basic Upload Setup
<template>
<PremiumBblEditor
v-model="content"
@ready="onEditorReady"
/>
</template>
<script>
import {
UploadManager,
LocalStorageAdapter,
integrateTipTapUpload,
createUploadConfig
} from 'vue2-premium-bbl-editor'
export default {
data() {
return {
content: '<p>Try uploading images...</p>',
uploadManager: null
}
},
async created() {
// Create upload configuration
const config = createUploadConfig('localStorage', {
validation: {
maxSize: 5 * 1024 * 1024, // 5MB
allowedTypes: ['image/jpeg', 'image/png', 'image/gif']
}
})
// Initialize upload manager
this.uploadManager = new UploadManager(config)
// Register local storage adapter
const adapter = new LocalStorageAdapter()
this.uploadManager.registerAdapter(adapter)
this.uploadManager.setDefaultAdapter('local-storage')
},
methods: {
onEditorReady(editor) {
// Integrate upload system with editor
integrateTipTapUpload(editor, this.uploadManager, {
onStart: () => console.log('Upload started'),
onEnd: () => console.log('Upload finished')
})
}
}
}
</script>Custom Upload Adapter
// Create custom adapter for your API
class CustomApiAdapter {
constructor(options) {
this.name = 'custom-api'
this.apiUrl = options.apiUrl
this.headers = options.headers || {}
}
async upload(file, options) {
const formData = new FormData()
formData.append('file', file)
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: this.headers,
body: formData
})
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`)
}
const result = await response.json()
return {
url: result.url,
size: file.size,
metadata: {
fileName: file.name,
fileType: file.type
}
}
}
}
// Register and use
const adapter = new CustomApiAdapter({
apiUrl: '/api/upload',
headers: { 'Authorization': 'Bearer your-token' }
})
uploadManager.registerAdapter(adapter)
uploadManager.setDefaultAdapter('custom-api')Upload Event Handling
// Listen to upload events
uploadManager.on('progress', (progress) => {
console.log(`Upload progress: ${progress.percentage}%`)
})
uploadManager.on('uploadCompleted', (event) => {
console.log('Upload completed:', event.result.url)
})
uploadManager.on('uploadFailed', (event) => {
console.error('Upload failed:', event.error.message)
})🧩 Individual Component Usage
Import and use individual components for custom implementations:
import {
PremiumBblEditor,
PremiumBblEditorOptionsAPI,
ToolbarMain,
ToolbarGroup,
ToolbarButton,
EditorBubbleMenu,
TableBubbleMenu,
ImageBubbleMenu,
VideoBubbleMenu,
ImageModal,
VideoModal,
LinkModal,
DiagnosticTool,
DebugHelper,
useEditor
} from 'vue2-premium-bbl-editor'Available Components
Main Components
PremiumBblEditor- Main editor component (Composition API)PremiumBblEditorOptionsAPI- Main editor component (Options API)DiagnosticTool- Built-in diagnostic and troubleshooting toolDebugHelper- Development debugging helper
Toolbar Components
ToolbarMain- Complete toolbar componentToolbarGroup- Toolbar button group containerToolbarButton- Individual toolbar button
Menu Components
EditorBubbleMenu- Text selection bubble menuTableBubbleMenu- Table-specific bubble menuImageBubbleMenu- Image-specific bubble menuVideoBubbleMenu- Video-specific bubble menu
Modal Components
ImageModal- Image upload and configuration modalVideoModal- Video upload and configuration modalLinkModal- Link creation and editing modal
Composables
useEditor- Core editor composable for custom implementations
Custom Implementation Example
<template>
<div class="custom-editor">
<ToolbarMain
v-if="editor"
:editor="editor"
:config="toolbarConfig"
@execute-command="executeCommand"
/>
<div class="editor-content">
<editor-content :editor="editor" />
</div>
<EditorBubbleMenu
v-if="editor"
:editor="editor"
:config="toolbarConfig"
/>
</div>
</template>
<script>
import { EditorContent } from '@tiptap/vue-2'
import { ToolbarMain, EditorBubbleMenu, useEditor } from 'vue2-premium-bbl-editor'
export default {
components: {
EditorContent,
ToolbarMain,
EditorBubbleMenu
},
setup() {
const { editor, executeCommand } = useEditor({
content: '<p>Custom editor implementation</p>',
extensions: [
// Your custom extensions
]
})
return {
editor,
executeCommand,
toolbarConfig: {
bold: true,
italic: true,
underline: true
}
}
}
}
</script>🔌 Extensions & Customization
The package includes custom extensions that enhance the editing experience:
Available Extensions
ResizableImage- Enhanced image handling with resize controlsResizableVideo- Video embedding with resize functionalityCustomTableCell- Enhanced table cell with controlsCustomTableHeader- Enhanced table header with controls
Using Extensions Directly
import { ResizableImage, ResizableVideo } from 'vue2-premium-bbl-editor'
import { Editor } from '@tiptap/vue-2'
const editor = new Editor({
extensions: [
ResizableImage.configure({
allowResize: true,
allowAlignment: true,
maxWidth: '800px'
}),
ResizableVideo.configure({
allowResize: true,
autoplay: false
})
]
})🌐 External Project Integration
For detailed integration instructions for external projects, see our External Integration Guide.
Quick Integration
# Install in your existing project
npm install vue2-premium-bbl-editor
# Install required dependencies
npm install @vue/composition-api @tiptap/core @tiptap/vue-2 @tiptap/starter-kit<template>
<PremiumBblEditor
v-model="content"
@ready="onEditorReady"
/>
</template>
<script>
import { PremiumBblEditor } from 'vue2-premium-bbl-editor'
export default {
components: { PremiumBblEditor },
data() {
return {
content: '<p>Start editing...</p>'
}
},
methods: {
onEditorReady(editor) {
console.log('Editor ready in external project!')
}
}
}
</script>🧪 Development & Testing
# Install dependencies
npm install
# Run development server
npm run serve
# Build library
npm run build:lib
# Run tests
npm test
# Lint code
npm run lintDevelopment Tools
The package includes built-in development and diagnostic tools:
<template>
<div>
<!-- Your editor -->
<PremiumBblEditor v-model="content" />
<!-- Development tools -->
<DiagnosticTool v-if="isDevelopment" />
<DebugHelper v-if="isDevelopment" />
</div>
</template>
<script>
import { PremiumBblEditor, DiagnosticTool, DebugHelper } from 'vue2-premium-bbl-editor'
export default {
components: {
PremiumBblEditor,
DiagnosticTool,
DebugHelper
},
computed: {
isDevelopment() {
return process.env.NODE_ENV === 'development'
}
}
}
</script>🔧 Troubleshooting
Common Issues
- Editor not loading: Check if all required dependencies are installed
- Upload not working: Verify upload handler configuration
- Styling issues: Ensure CSS is properly imported
- TypeScript errors: Check type definitions import
Diagnostic Tools
Use the built-in diagnostic tool to identify issues:
<template>
<div>
<PremiumBblEditor v-model="content" />
<DiagnosticTool />
</div>
</template>Debug Mode
Enable debug mode for detailed logging:
<template>
<PremiumBblEditor
v-model="content"
:debug="true"
/>
</template>For more troubleshooting help, see TROUBLESHOOTING.md.
📚 Documentation
- Installation Guide
- External Integration Guide
- Upload System Documentation
- Troubleshooting Guide
- API Reference
- Examples
📄 License
MIT License - see LICENSE file for details.
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📞 Support
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
- 📖 Documentation: Full Documentation
🙏 Acknowledgments
- Tiptap - The headless editor framework
- ProseMirror - The foundation
- Vue.js - The progressive framework
