@mpdev_ab/document-creator 0.1.1 → 0.2.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 CHANGED
@@ -22,7 +22,7 @@ npm install vue@^3.3.0 @tiptap/core @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit
22
22
  <template>
23
23
  <DocumentEditor
24
24
  v-model="content"
25
- :api="api"
25
+ @save="onSave"
26
26
  />
27
27
  </template>
28
28
 
@@ -32,11 +32,9 @@ import { DocumentEditor } from '@mpdev_ab/document-creator'
32
32
 
33
33
  const content = ref('')
34
34
 
35
- const api = {
36
- saveDocument: '/api/documents',
37
- saveTemplate: '/api/templates',
38
- loadTemplates: '/api/templates',
39
- deleteTemplate: '/api/templates',
35
+ function onSave(html) {
36
+ // html is a string — send it to your API however you like
37
+ console.log(html)
40
38
  }
41
39
  </script>
42
40
  ```
@@ -58,7 +56,7 @@ Then use it in any page/component:
58
56
  ```vue
59
57
  <template>
60
58
  <ClientOnly>
61
- <DocumentEditor v-model="content" :api="api" />
59
+ <DocumentEditor v-model="content" @save="onSave" />
62
60
  </ClientOnly>
63
61
  </template>
64
62
  ```
@@ -70,9 +68,8 @@ Wrap in `<ClientOnly>` since the editor requires the DOM.
70
68
  | Prop | Type | Required | Default | Description |
71
69
  |------|------|----------|---------|-------------|
72
70
  | `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 |
71
+ | `templates` | `Template[]` | No | `[]` | List of templates to show in the load modal |
72
+ | `templatesLoading` | `boolean` | No | `false` | Shows loading state in the load templates modal |
76
73
  | `image` | `ImageConfig` | No | `{ maxSize: 5MB, allowedTypes: ['image/jpeg', 'image/png', 'image/gif'] }` | Image upload constraints |
77
74
  | `theme` | `Partial<ThemeConfig>` | No | See defaults below | Tailwind class overrides |
78
75
  | `placeholder` | `string` | No | `''` | Placeholder text when editor is empty |
@@ -83,36 +80,110 @@ Wrap in `<ClientOnly>` since the editor requires the DOM.
83
80
  | Event | Payload | Description |
84
81
  |-------|---------|-------------|
85
82
  | `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 |
83
+ | `save` | `string` | Emitted with the HTML string when the user clicks Save |
84
+ | `saveTemplate` | `{ name: string, type: 'document' \| 'snippet', content: string }` | Emitted when the user saves a template |
85
+ | `loadTemplates` | — | Emitted when the load templates modal opens — fetch your templates and pass them via the `templates` prop |
86
+ | `deleteTemplate` | `Template` | Emitted when the user clicks delete on a template |
87
+ | `error` | `{ message: string, detail: unknown }` | Emitted on image upload errors |
88
88
 
89
- ## ApiConfig (required)
89
+ ## How saving works
90
90
 
91
- All four endpoint URLs are required. The component uses `fetch` with `POST` method and `Content-Type: application/json`.
91
+ The editor does **not** make any API calls. When the user clicks Save, it emits the `save` event with the HTML string. Your app handles persistence:
92
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
- },
93
+ ```vue
94
+ <template>
95
+ <DocumentEditor v-model="content" @save="onSave" />
96
+ </template>
97
+
98
+ <script setup>
99
+ import { ref } from 'vue'
100
+ import { DocumentEditor } from '@mpdev_ab/document-creator'
101
+ import { useMutation } from '@vue/apollo-composable'
102
+ import gql from 'graphql-tag'
103
+
104
+ const content = ref('')
105
+
106
+ const SAVE_DOCUMENT = gql`
107
+ mutation SaveDocument($content: String!) {
108
+ saveDocument(content: $content) {
109
+ id
110
+ }
111
+ }
112
+ `
113
+
114
+ const { mutate } = useMutation(SAVE_DOCUMENT)
115
+
116
+ async function onSave(html) {
117
+ await mutate({ content: html })
102
118
  }
119
+ </script>
103
120
  ```
104
121
 
105
- ### Expected API responses
122
+ ## Templates
123
+
124
+ Templates are managed by your app. The editor emits events — you handle fetching, saving, and deleting.
125
+
126
+ ```vue
127
+ <template>
128
+ <DocumentEditor
129
+ v-model="content"
130
+ :templates="templates"
131
+ :templates-loading="loading"
132
+ @save="onSave"
133
+ @load-templates="fetchTemplates"
134
+ @save-template="onSaveTemplate"
135
+ @delete-template="onDeleteTemplate"
136
+ />
137
+ </template>
138
+
139
+ <script setup>
140
+ import { ref } from 'vue'
141
+ import { DocumentEditor } from '@mpdev_ab/document-creator'
142
+
143
+ const content = ref('')
144
+ const templates = ref([])
145
+ const loading = ref(false)
146
+
147
+ async function fetchTemplates() {
148
+ loading.value = true
149
+ // Fetch from your GraphQL API, REST, etc.
150
+ const result = await yourApi.getTemplates()
151
+ templates.value = result // must be { id, name, type, content }[]
152
+ loading.value = false
153
+ }
154
+
155
+ async function onSave(html) {
156
+ await yourApi.saveDocument(html)
157
+ }
106
158
 
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
- ]
159
+ async function onSaveTemplate(data) {
160
+ // data = { name: string, type: 'document' | 'snippet', content: string }
161
+ await yourApi.createTemplate(data)
162
+ await fetchTemplates() // refresh the list
163
+ }
164
+
165
+ async function onDeleteTemplate(template) {
166
+ // template = { id, name, type, content }
167
+ await yourApi.deleteTemplate(template.id)
168
+ await fetchTemplates() // refresh the list
169
+ }
170
+ </script>
171
+ ```
172
+
173
+ ### Template object shape
174
+
175
+ ```ts
176
+ interface Template {
177
+ id: string | number
178
+ name: string
179
+ type: 'document' | 'snippet'
180
+ content: string
181
+ }
113
182
  ```
114
183
 
115
- **DELETE deleteTemplate** — called as `DELETE {deleteTemplate}/{id}`
184
+ Template types:
185
+ - `document` — replaces the entire editor content when loaded
186
+ - `snippet` — inserts at the cursor position when loaded
116
187
 
117
188
  ## ImageConfig
118
189
 
@@ -132,7 +203,6 @@ Override any part of the default Tailwind classes:
132
203
  ```vue
133
204
  <DocumentEditor
134
205
  v-model="content"
135
- :api="api"
136
206
  :theme="{
137
207
  toolbar: 'bg-gray-900 border-b border-gray-700 p-2 flex flex-wrap items-center gap-1',
138
208
  toolbarButton: 'hover:bg-gray-700 rounded p-1.5 text-gray-300 cursor-pointer',
@@ -181,47 +251,24 @@ if (isEmpty()) {
181
251
 
182
252
  This must be called from a component that is a child of `<DocumentEditor>`.
183
253
 
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
254
  ## Full example
205
255
 
206
256
  ```vue
207
257
  <template>
208
258
  <DocumentEditor
209
259
  v-model="content"
210
- mode="document"
211
260
  placeholder="Write your document..."
212
261
  :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
- }"
262
+ :templates="templates"
263
+ :templates-loading="templatesLoading"
220
264
  :image="{
221
265
  maxSize: 10 * 1024 * 1024,
222
266
  allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
223
267
  }"
224
268
  @save="onSave"
269
+ @save-template="onSaveTemplate"
270
+ @load-templates="onLoadTemplates"
271
+ @delete-template="onDeleteTemplate"
225
272
  @error="onError"
226
273
  />
227
274
  </template>
@@ -231,10 +278,25 @@ import { ref } from 'vue'
231
278
  import { DocumentEditor } from '@mpdev_ab/document-creator'
232
279
 
233
280
  const content = ref('<p>Hello world</p>')
234
- const token = 'your-auth-token'
281
+ const templates = ref([])
282
+ const templatesLoading = ref(false)
283
+
284
+ function onSave(html) {
285
+ // Send html to your backend
286
+ }
287
+
288
+ function onSaveTemplate(data) {
289
+ // data = { name, type, content }
290
+ }
291
+
292
+ async function onLoadTemplates() {
293
+ templatesLoading.value = true
294
+ templates.value = await fetchTemplatesFromApi()
295
+ templatesLoading.value = false
296
+ }
235
297
 
236
- function onSave(response) {
237
- console.log('Saved:', response)
298
+ function onDeleteTemplate(template) {
299
+ // template = { id, name, type, content }
238
300
  }
239
301
 
240
302
  function onError(error) {