@kvass/rich-text 1.3.3 → 1.4.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/package.json
CHANGED
package/src/Component.vue
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="richtext">
|
|
3
|
-
<BubbleMenu v-if="editor" :editor="editor">
|
|
4
|
-
<div class="richtext__bubble">
|
|
2
|
+
<div class="richtext" :class="{ 'richtext--disabled': disabled }">
|
|
3
|
+
<BubbleMenu v-if="editor" :editor="editor" :should-show="bubbleShouldShow">
|
|
4
|
+
<div ref="bubble" class="richtext__bubble">
|
|
5
5
|
<form
|
|
6
6
|
class="richtext__bubble-form"
|
|
7
|
-
v-
|
|
7
|
+
v-show="['link', 'cta'].includes(bubbleState)"
|
|
8
8
|
@submit.prevent="setLink(linkUrl)"
|
|
9
9
|
>
|
|
10
10
|
<input
|
|
@@ -13,9 +13,15 @@
|
|
|
13
13
|
v-model="linkUrl"
|
|
14
14
|
placeholder="https://"
|
|
15
15
|
ref="linkInput"
|
|
16
|
-
autofocus
|
|
17
16
|
@keydown.esc="bubbleState = null"
|
|
18
17
|
/>
|
|
18
|
+
<select v-if="bubbleState === 'cta'" v-model="bubbleOptions.theme">
|
|
19
|
+
<option value="primary">{{ labels.primary }}</option>
|
|
20
|
+
<option value="secondary">{{ labels.secondary }}</option>
|
|
21
|
+
</select>
|
|
22
|
+
<button @click="setLink(linkUrl)" :disabled="!linkUrl" type="button">
|
|
23
|
+
<FontAwesomeIcon :icon="['far', 'check']" />
|
|
24
|
+
</button>
|
|
19
25
|
<button @click="setLink(null)" type="button">
|
|
20
26
|
<FontAwesomeIcon :icon="['far', 'times']" />
|
|
21
27
|
</button>
|
|
@@ -25,7 +31,9 @@
|
|
|
25
31
|
<button
|
|
26
32
|
v-for="(item, index) in getCommands('bubble')"
|
|
27
33
|
:key="'bubble' + index"
|
|
34
|
+
class="richtext__bubble-button"
|
|
28
35
|
:class="{ 'is-active': editor.isActive(item.stateKey) }"
|
|
36
|
+
:disabled="disabled || item.disabled"
|
|
29
37
|
@click="
|
|
30
38
|
item.customFunc
|
|
31
39
|
? item.customFunc()
|
|
@@ -39,19 +47,26 @@
|
|
|
39
47
|
</div>
|
|
40
48
|
</BubbleMenu>
|
|
41
49
|
|
|
42
|
-
<
|
|
43
|
-
<button
|
|
44
|
-
v-for="(item, index) in getCommands('menu')"
|
|
45
|
-
:key="'menubar' + index"
|
|
46
|
-
type="button"
|
|
47
|
-
:class="{ 'is-active': editor.isActive(item.stateKey) }"
|
|
48
|
-
@click="editor.chain().focus()[item.commandKey](item.commandProps).run()"
|
|
49
|
-
>
|
|
50
|
-
<FontAwesomeIcon :icon="item.icon" size="sm" />
|
|
51
|
-
</button>
|
|
52
|
-
</div>
|
|
50
|
+
<EditorContent class="richtext__editor" ref="editor" :editor="editor" :editable="!disabled" />
|
|
53
51
|
|
|
54
|
-
<
|
|
52
|
+
<div v-if="editor" class="richtext__menubar">
|
|
53
|
+
<div class="richtext__menubar-buttons">
|
|
54
|
+
<button
|
|
55
|
+
v-for="(item, index) in getCommands('menu')"
|
|
56
|
+
:key="'menubar' + index"
|
|
57
|
+
type="button"
|
|
58
|
+
:class="{ 'is-active': editor.isActive(item.stateKey) }"
|
|
59
|
+
:disabled="disabled || item.disabled"
|
|
60
|
+
@click="
|
|
61
|
+
item.customFunc
|
|
62
|
+
? item.customFunc()
|
|
63
|
+
: editor.chain().focus()[item.commandKey](item.commandProps).run()
|
|
64
|
+
"
|
|
65
|
+
>
|
|
66
|
+
<FontAwesomeIcon :icon="item.icon" size="sm" />
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
55
70
|
</div>
|
|
56
71
|
</template>
|
|
57
72
|
|
|
@@ -59,10 +74,11 @@
|
|
|
59
74
|
import { Editor, EditorContent, BubbleMenu } from '@tiptap/vue-2'
|
|
60
75
|
import Link from '@tiptap/extension-link'
|
|
61
76
|
import Image from '@tiptap/extension-image'
|
|
62
|
-
import CallToAction from './extensions/
|
|
77
|
+
import CallToAction from './extensions/cta'
|
|
63
78
|
import StarterKit from '@tiptap/starter-kit'
|
|
64
79
|
|
|
65
80
|
const DefaultCommands = ['heading', 'bold', 'italic', 'orderedList', 'bulletList', 'link', 'cta']
|
|
81
|
+
const DefaultLabels = { primary: 'Primær', secondary: 'Sekundær' }
|
|
66
82
|
|
|
67
83
|
export { DefaultCommands }
|
|
68
84
|
export default {
|
|
@@ -76,18 +92,32 @@ export default {
|
|
|
76
92
|
type: Array,
|
|
77
93
|
default: () => DefaultCommands,
|
|
78
94
|
},
|
|
95
|
+
labels: {
|
|
96
|
+
type: Object,
|
|
97
|
+
default: () => DefaultLabels,
|
|
98
|
+
},
|
|
79
99
|
},
|
|
80
100
|
watch: {
|
|
81
101
|
value(value) {
|
|
82
102
|
if (this.editor.getHTML() === value) return
|
|
83
103
|
this.editor.commands.setContent(this.value, false)
|
|
84
104
|
},
|
|
105
|
+
disabled(value) {
|
|
106
|
+
if (!this.editor) return
|
|
107
|
+
this.editor.setOptions({ editable: !value })
|
|
108
|
+
},
|
|
109
|
+
bubbleState(value) {
|
|
110
|
+
if (!value) return
|
|
111
|
+
this.$refs.editor.$el.children[0].focus()
|
|
112
|
+
setTimeout(() => this.$refs.linkInput.focus(), 1)
|
|
113
|
+
},
|
|
85
114
|
},
|
|
86
115
|
data() {
|
|
87
116
|
return {
|
|
88
117
|
editor: null,
|
|
89
118
|
linkUrl: null,
|
|
90
119
|
bubbleState: null,
|
|
120
|
+
bubbleOptions: { theme: 'primary' },
|
|
91
121
|
}
|
|
92
122
|
},
|
|
93
123
|
computed: {
|
|
@@ -109,7 +139,7 @@ export default {
|
|
|
109
139
|
icon: ['far', 'bold'],
|
|
110
140
|
appearance: {
|
|
111
141
|
menu: true,
|
|
112
|
-
bubble:
|
|
142
|
+
bubble: false,
|
|
113
143
|
},
|
|
114
144
|
},
|
|
115
145
|
{
|
|
@@ -118,7 +148,7 @@ export default {
|
|
|
118
148
|
icon: ['far', 'italic'],
|
|
119
149
|
appearance: {
|
|
120
150
|
menu: true,
|
|
121
|
-
bubble:
|
|
151
|
+
bubble: false,
|
|
122
152
|
},
|
|
123
153
|
},
|
|
124
154
|
{
|
|
@@ -145,10 +175,11 @@ export default {
|
|
|
145
175
|
customFunc: () => {
|
|
146
176
|
this.bubbleState = 'link'
|
|
147
177
|
},
|
|
178
|
+
disabled: this.editor.state.selection.empty,
|
|
148
179
|
icon: ['far', 'link'],
|
|
149
180
|
appearance: {
|
|
150
|
-
menu:
|
|
151
|
-
bubble:
|
|
181
|
+
menu: true,
|
|
182
|
+
bubble: false,
|
|
152
183
|
},
|
|
153
184
|
},
|
|
154
185
|
{
|
|
@@ -167,10 +198,11 @@ export default {
|
|
|
167
198
|
customFunc: () => {
|
|
168
199
|
this.bubbleState = 'cta'
|
|
169
200
|
},
|
|
201
|
+
disabled: this.editor.state.selection.empty,
|
|
170
202
|
icon: ['far', 'mouse-pointer'],
|
|
171
203
|
appearance: {
|
|
172
|
-
menu:
|
|
173
|
-
bubble:
|
|
204
|
+
menu: true,
|
|
205
|
+
bubble: false,
|
|
174
206
|
},
|
|
175
207
|
},
|
|
176
208
|
]
|
|
@@ -191,7 +223,7 @@ export default {
|
|
|
191
223
|
else editor.unsetLink().run()
|
|
192
224
|
break
|
|
193
225
|
case 'cta':
|
|
194
|
-
if (value) editor.setCta({ href: value }).run()
|
|
226
|
+
if (value) editor.setCta({ href: value, 'data-cta': this.bubbleOptions.theme }).run()
|
|
195
227
|
else editor.unsetCta().run()
|
|
196
228
|
break
|
|
197
229
|
}
|
|
@@ -199,6 +231,14 @@ export default {
|
|
|
199
231
|
this.bubbleState = null
|
|
200
232
|
this.linkUrl = null
|
|
201
233
|
},
|
|
234
|
+
bubbleShouldShow({ editor }) {
|
|
235
|
+
return (
|
|
236
|
+
this.availableCommands
|
|
237
|
+
.filter(a => a.appearance.bubble)
|
|
238
|
+
.map(a => a.stateKey)
|
|
239
|
+
.some(k => editor.isActive(k)) || !this.editor.state.selection.empty
|
|
240
|
+
)
|
|
241
|
+
},
|
|
202
242
|
},
|
|
203
243
|
mounted() {
|
|
204
244
|
this.editor = new Editor({
|
|
@@ -226,11 +266,25 @@ export default {
|
|
|
226
266
|
@import './styles/_mixins';
|
|
227
267
|
.richtext {
|
|
228
268
|
flex-grow: 1;
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-direction: column-reverse;
|
|
271
|
+
|
|
272
|
+
&--disabled {
|
|
273
|
+
background-color: var(--vue-elder-input-color, #fafafa);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
&:not(.richtext--disabled):focus-within {
|
|
277
|
+
outline: 1px solid var(--primary);
|
|
278
|
+
border-radius: var(--border-radius, 3px);
|
|
279
|
+
}
|
|
229
280
|
|
|
230
281
|
&__editor {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
282
|
+
flex-grow: 1;
|
|
283
|
+
|
|
284
|
+
.ProseMirror {
|
|
285
|
+
padding: 0rem 1rem 1rem;
|
|
286
|
+
min-height: 6rem;
|
|
287
|
+
height: 100%;
|
|
234
288
|
|
|
235
289
|
p:first-child {
|
|
236
290
|
margin-top: 0;
|
|
@@ -244,48 +298,73 @@ export default {
|
|
|
244
298
|
}
|
|
245
299
|
|
|
246
300
|
&:focus {
|
|
247
|
-
outline:
|
|
248
|
-
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
301
|
+
outline: none;
|
|
249
302
|
}
|
|
250
303
|
|
|
251
304
|
img {
|
|
252
305
|
max-width: 100%;
|
|
253
306
|
}
|
|
254
307
|
|
|
255
|
-
a[data-cta
|
|
256
|
-
background-color: var(--primary);
|
|
257
|
-
color: white;
|
|
308
|
+
a[data-cta] {
|
|
258
309
|
padding: 0.75em 1.5em;
|
|
259
310
|
border-radius: var(--border-radius);
|
|
260
311
|
text-decoration: none;
|
|
261
312
|
|
|
262
313
|
display: inline-block;
|
|
263
314
|
}
|
|
264
|
-
}
|
|
265
315
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
316
|
+
a[data-cta='primary'] {
|
|
317
|
+
background-color: var(--primary);
|
|
318
|
+
color: var(--primary-contrast);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
a[data-cta='secondary'] {
|
|
322
|
+
background-color: var(--secondary);
|
|
323
|
+
color: var(--secondary-contrast);
|
|
324
|
+
}
|
|
269
325
|
}
|
|
270
326
|
}
|
|
271
327
|
|
|
272
328
|
&__bubble {
|
|
273
329
|
display: flex;
|
|
274
330
|
background-color: var(--dark);
|
|
331
|
+
color: white;
|
|
275
332
|
border-radius: var(--border-radius);
|
|
276
333
|
|
|
277
334
|
&-form {
|
|
278
335
|
display: flex;
|
|
279
336
|
|
|
337
|
+
button,
|
|
338
|
+
select {
|
|
339
|
+
background-color: transparent;
|
|
340
|
+
color: inherit;
|
|
341
|
+
border: none;
|
|
342
|
+
border-left: 1px solid rgba(white, 0.1);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
option {
|
|
346
|
+
color: black;
|
|
347
|
+
}
|
|
348
|
+
|
|
280
349
|
button {
|
|
281
|
-
padding: 0.5rem
|
|
350
|
+
padding: 0.5rem;
|
|
351
|
+
min-width: 2.5rem;
|
|
352
|
+
|
|
353
|
+
&:disabled {
|
|
354
|
+
opacity: 0.5;
|
|
355
|
+
background-color: rgba(white, 0.1);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
select {
|
|
360
|
+
padding: 0.5rem !important;
|
|
282
361
|
}
|
|
283
362
|
}
|
|
284
363
|
|
|
285
364
|
&-input {
|
|
286
365
|
font: inherit;
|
|
287
366
|
border: none;
|
|
288
|
-
padding:
|
|
367
|
+
padding: 0.5rem;
|
|
289
368
|
background-color: transparent;
|
|
290
369
|
color: #fff !important;
|
|
291
370
|
|
|
@@ -294,9 +373,8 @@ export default {
|
|
|
294
373
|
}
|
|
295
374
|
}
|
|
296
375
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
width: initial !important;
|
|
376
|
+
&__button {
|
|
377
|
+
width: initial;
|
|
300
378
|
padding: 0.5rem 0.75rem !important;
|
|
301
379
|
color: white;
|
|
302
380
|
|
|
@@ -316,24 +394,60 @@ export default {
|
|
|
316
394
|
}
|
|
317
395
|
|
|
318
396
|
&__menubar {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
397
|
+
padding: 0.75rem;
|
|
398
|
+
position: sticky;
|
|
399
|
+
top: 0;
|
|
400
|
+
z-index: 1;
|
|
401
|
+
|
|
402
|
+
&-buttons {
|
|
403
|
+
width: max-content;
|
|
404
|
+
box-shadow: 0 2px 4px -2px rgba(black, 0.1);
|
|
405
|
+
}
|
|
322
406
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
407
|
+
button {
|
|
408
|
+
padding: 0.5rem;
|
|
409
|
+
min-width: 2.5rem;
|
|
410
|
+
border: 1px solid var(--border-color);
|
|
411
|
+
cursor: pointer;
|
|
412
|
+
background-color: #ffffff;
|
|
413
|
+
|
|
414
|
+
&:focus-visible {
|
|
415
|
+
position: relative;
|
|
416
|
+
border-radius: var(--border-radius, 3px);
|
|
417
|
+
outline: 1px solid var(--primary) !important;
|
|
418
|
+
}
|
|
329
419
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
420
|
+
&:first-child {
|
|
421
|
+
border-top-left-radius: var(--border-radius, 3px);
|
|
422
|
+
border-bottom-left-radius: var(--border-radius, 3px);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
&:last-child {
|
|
426
|
+
border-top-right-radius: var(--border-radius, 3px);
|
|
427
|
+
border-bottom-right-radius: var(--border-radius, 3px);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
& + button {
|
|
431
|
+
border-left: none;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
&:disabled {
|
|
435
|
+
cursor: not-allowed;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
&:hover:not(:disabled),
|
|
439
|
+
&.is-active {
|
|
440
|
+
background-color: darken(#ffffff, 3%);
|
|
441
|
+
}
|
|
333
442
|
}
|
|
334
443
|
}
|
|
444
|
+
|
|
335
445
|
a {
|
|
336
446
|
word-break: break-all;
|
|
337
447
|
}
|
|
448
|
+
|
|
449
|
+
.tippy-box {
|
|
450
|
+
max-width: initial !important;
|
|
451
|
+
}
|
|
338
452
|
}
|
|
339
453
|
</style>
|
|
File without changes
|