@mpdev_ab/document-creator 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# @mpdev_ab/document-creator
|
|
2
|
+
|
|
3
|
+
A rich text editor Vue 3 component built on Tiptap. Drop-in replacement for TinyMCE with font selection, tables, image upload (base64), templates, and full formatting — outputs HTML.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mpdev_ab/document-creator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer dependencies
|
|
12
|
+
|
|
13
|
+
Your project needs Vue 3 and the Tiptap packages:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install vue@^3.3.0 @tiptap/core @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit @tiptap/extension-text-style @tiptap/extension-font-family @tiptap/extension-image @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-cell @tiptap/extension-table-header @tiptap/extension-underline @tiptap/extension-subscript @tiptap/extension-superscript @tiptap/extension-text-align @tiptap/extension-link @tiptap/extension-color @tiptap/extension-placeholder
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Basic usage
|
|
20
|
+
|
|
21
|
+
```vue
|
|
22
|
+
<template>
|
|
23
|
+
<DocumentEditor
|
|
24
|
+
v-model="content"
|
|
25
|
+
:api="api"
|
|
26
|
+
/>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup>
|
|
30
|
+
import { ref } from 'vue'
|
|
31
|
+
import { DocumentEditor } from '@mpdev_ab/document-creator'
|
|
32
|
+
|
|
33
|
+
const content = ref('')
|
|
34
|
+
|
|
35
|
+
const api = {
|
|
36
|
+
saveDocument: '/api/documents',
|
|
37
|
+
saveTemplate: '/api/templates',
|
|
38
|
+
loadTemplates: '/api/templates',
|
|
39
|
+
deleteTemplate: '/api/templates',
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Nuxt 3
|
|
45
|
+
|
|
46
|
+
Create a plugin at `plugins/document-creator.client.ts`:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { DocumentEditor } from '@mpdev_ab/document-creator'
|
|
50
|
+
|
|
51
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
52
|
+
nuxtApp.vueApp.component('DocumentEditor', DocumentEditor)
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then use it in any page/component:
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<template>
|
|
60
|
+
<ClientOnly>
|
|
61
|
+
<DocumentEditor v-model="content" :api="api" />
|
|
62
|
+
</ClientOnly>
|
|
63
|
+
</template>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Wrap in `<ClientOnly>` since the editor requires the DOM.
|
|
67
|
+
|
|
68
|
+
## Props
|
|
69
|
+
|
|
70
|
+
| Prop | Type | Required | Default | Description |
|
|
71
|
+
|------|------|----------|---------|-------------|
|
|
72
|
+
| `v-model` | `string` | Yes | — | HTML content (two-way binding) |
|
|
73
|
+
| `api` | `ApiConfig` | Yes | — | API endpoint URLs for save/templates |
|
|
74
|
+
| `mode` | `'document' \| 'template'` | No | `'document'` | Determines which save endpoint is used |
|
|
75
|
+
| `templateMeta` | `TemplateMeta` | No | — | Name and type sent when saving in template mode |
|
|
76
|
+
| `image` | `ImageConfig` | No | `{ maxSize: 5MB, allowedTypes: ['image/jpeg', 'image/png', 'image/gif'] }` | Image upload constraints |
|
|
77
|
+
| `theme` | `Partial<ThemeConfig>` | No | See defaults below | Tailwind class overrides |
|
|
78
|
+
| `placeholder` | `string` | No | `''` | Placeholder text when editor is empty |
|
|
79
|
+
| `readonly` | `boolean` | No | `false` | Hides toolbar and disables editing |
|
|
80
|
+
|
|
81
|
+
## Events
|
|
82
|
+
|
|
83
|
+
| Event | Payload | Description |
|
|
84
|
+
|-------|---------|-------------|
|
|
85
|
+
| `update:modelValue` | `string` | Emitted on every content change (used by v-model) |
|
|
86
|
+
| `save` | `unknown` | Emitted with the API response after a successful save |
|
|
87
|
+
| `error` | `{ message: string; detail: unknown }` | Emitted on save/template/image errors |
|
|
88
|
+
|
|
89
|
+
## ApiConfig (required)
|
|
90
|
+
|
|
91
|
+
All four endpoint URLs are required. The component uses `fetch` with `POST` method and `Content-Type: application/json`.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const api = {
|
|
95
|
+
saveDocument: '/api/documents', // POST { content: "<html>" }
|
|
96
|
+
saveTemplate: '/api/templates', // POST { name, type, content }
|
|
97
|
+
loadTemplates: '/api/templates', // GET — must return Template[]
|
|
98
|
+
deleteTemplate: '/api/templates', // DELETE /{id}
|
|
99
|
+
headers: { // Optional — added to all requests
|
|
100
|
+
'Authorization': 'Bearer your-token',
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Expected API responses
|
|
106
|
+
|
|
107
|
+
**GET loadTemplates** — return an array:
|
|
108
|
+
```json
|
|
109
|
+
[
|
|
110
|
+
{ "id": 1, "name": "Invoice", "type": "document", "content": "<h1>Invoice</h1>..." },
|
|
111
|
+
{ "id": 2, "name": "Signature", "type": "snippet", "content": "<p>Regards,</p>..." }
|
|
112
|
+
]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**DELETE deleteTemplate** — called as `DELETE {deleteTemplate}/{id}`
|
|
116
|
+
|
|
117
|
+
## ImageConfig
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const imageConfig = {
|
|
121
|
+
maxSize: 10 * 1024 * 1024, // 10MB (default: 5MB)
|
|
122
|
+
allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Images are converted to base64 and stored inline in the HTML. After inserting, users can resize images using preset buttons (25%, 50%, 75%, 100%) or enter a custom width.
|
|
127
|
+
|
|
128
|
+
## ThemeConfig
|
|
129
|
+
|
|
130
|
+
Override any part of the default Tailwind classes:
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<DocumentEditor
|
|
134
|
+
v-model="content"
|
|
135
|
+
:api="api"
|
|
136
|
+
:theme="{
|
|
137
|
+
toolbar: 'bg-gray-900 border-b border-gray-700 p-2 flex flex-wrap items-center gap-1',
|
|
138
|
+
toolbarButton: 'hover:bg-gray-700 rounded p-1.5 text-gray-300 cursor-pointer',
|
|
139
|
+
toolbarButtonActive: 'bg-blue-900 text-blue-300',
|
|
140
|
+
editor: 'bg-gray-800 text-white min-h-[400px] p-4 prose prose-invert max-w-none',
|
|
141
|
+
dropdown: 'bg-gray-800 border border-gray-700 rounded shadow-lg py-1 z-50',
|
|
142
|
+
modal: 'bg-gray-800 text-white rounded-lg shadow-xl p-6',
|
|
143
|
+
saveButton: 'bg-blue-500 text-white rounded px-4 py-2 hover:bg-blue-600',
|
|
144
|
+
}"
|
|
145
|
+
/>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Defaults:**
|
|
149
|
+
| Key | Default classes |
|
|
150
|
+
|-----|----------------|
|
|
151
|
+
| `toolbar` | `bg-white border-b border-gray-200 p-2 flex flex-wrap items-center gap-1` |
|
|
152
|
+
| `toolbarButton` | `hover:bg-gray-100 rounded p-1.5 text-gray-600 cursor-pointer` |
|
|
153
|
+
| `toolbarButtonActive` | `bg-blue-100 text-blue-600` |
|
|
154
|
+
| `editor` | `bg-white min-h-[400px] p-4 prose max-w-none focus:outline-none` |
|
|
155
|
+
| `dropdown` | `bg-white border border-gray-200 rounded shadow-lg py-1 z-50` |
|
|
156
|
+
| `modal` | `bg-white rounded-lg shadow-xl p-6` |
|
|
157
|
+
| `saveButton` | `bg-blue-600 text-white rounded px-4 py-2 hover:bg-blue-700` |
|
|
158
|
+
|
|
159
|
+
## useDocumentEditor composable
|
|
160
|
+
|
|
161
|
+
Access the editor instance from child components:
|
|
162
|
+
|
|
163
|
+
```vue
|
|
164
|
+
<script setup>
|
|
165
|
+
import { useDocumentEditor } from '@mpdev_ab/document-creator'
|
|
166
|
+
|
|
167
|
+
const { editor, getHTML, getText, setContent, focus, isEmpty } = useDocumentEditor()
|
|
168
|
+
|
|
169
|
+
// Get current HTML
|
|
170
|
+
const html = getHTML()
|
|
171
|
+
|
|
172
|
+
// Set content programmatically
|
|
173
|
+
setContent('<p>New content</p>')
|
|
174
|
+
|
|
175
|
+
// Check if empty
|
|
176
|
+
if (isEmpty()) {
|
|
177
|
+
// ...
|
|
178
|
+
}
|
|
179
|
+
</script>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This must be called from a component that is a child of `<DocumentEditor>`.
|
|
183
|
+
|
|
184
|
+
## Template mode
|
|
185
|
+
|
|
186
|
+
Save the editor content as a reusable template:
|
|
187
|
+
|
|
188
|
+
```vue
|
|
189
|
+
<DocumentEditor
|
|
190
|
+
v-model="content"
|
|
191
|
+
mode="template"
|
|
192
|
+
:template-meta="{ name: 'My Template', type: 'document' }"
|
|
193
|
+
:api="api"
|
|
194
|
+
@save="(res) => console.log('Template saved', res)"
|
|
195
|
+
/>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
When `mode="template"`, clicking Save sends `{ name, type, content }` to `api.saveTemplate` instead of `api.saveDocument`.
|
|
199
|
+
|
|
200
|
+
Template types:
|
|
201
|
+
- `document` — replaces the entire editor content when loaded
|
|
202
|
+
- `snippet` — inserts at the cursor position when loaded
|
|
203
|
+
|
|
204
|
+
## Full example
|
|
205
|
+
|
|
206
|
+
```vue
|
|
207
|
+
<template>
|
|
208
|
+
<DocumentEditor
|
|
209
|
+
v-model="content"
|
|
210
|
+
mode="document"
|
|
211
|
+
placeholder="Write your document..."
|
|
212
|
+
:readonly="false"
|
|
213
|
+
:api="{
|
|
214
|
+
saveDocument: '/api/documents',
|
|
215
|
+
saveTemplate: '/api/templates',
|
|
216
|
+
loadTemplates: '/api/templates',
|
|
217
|
+
deleteTemplate: '/api/templates',
|
|
218
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
219
|
+
}"
|
|
220
|
+
:image="{
|
|
221
|
+
maxSize: 10 * 1024 * 1024,
|
|
222
|
+
allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
|
223
|
+
}"
|
|
224
|
+
@save="onSave"
|
|
225
|
+
@error="onError"
|
|
226
|
+
/>
|
|
227
|
+
</template>
|
|
228
|
+
|
|
229
|
+
<script setup>
|
|
230
|
+
import { ref } from 'vue'
|
|
231
|
+
import { DocumentEditor } from '@mpdev_ab/document-creator'
|
|
232
|
+
|
|
233
|
+
const content = ref('<p>Hello world</p>')
|
|
234
|
+
const token = 'your-auth-token'
|
|
235
|
+
|
|
236
|
+
function onSave(response) {
|
|
237
|
+
console.log('Saved:', response)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function onError(error) {
|
|
241
|
+
console.error(error.message, error.detail)
|
|
242
|
+
}
|
|
243
|
+
</script>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Features
|
|
247
|
+
|
|
248
|
+
- Bold, italic, underline, strikethrough, subscript, superscript
|
|
249
|
+
- Font family (web-safe fonts), font size, font color
|
|
250
|
+
- Text alignment (left, center, right, justify)
|
|
251
|
+
- Line height
|
|
252
|
+
- Headings (H1-H6) and paragraph
|
|
253
|
+
- Bullet lists, numbered lists, blockquotes, horizontal rules
|
|
254
|
+
- Links with URL input
|
|
255
|
+
- Image upload (base64) with in-editor resize (25/50/75/100% presets + custom width)
|
|
256
|
+
- Tables with Google Docs-style grid picker, row/column operations, merge/split cells, header toggle, cell background color, column resize
|
|
257
|
+
- Video embed (YouTube/Vimeo URL)
|
|
258
|
+
- Save/load templates (full documents and snippets)
|
|
259
|
+
- Readonly mode
|
|
260
|
+
- Tailwind CSS theming via class string props
|