tiptapify 0.0.1 → 0.0.4

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.
@@ -0,0 +1,697 @@
1
+ import { computed, ComputedRef, Ref, ref } from "vue";
2
+ import * as mdi from '@mdi/js'
3
+
4
+ const fonts = ref([
5
+ {
6
+ name: 'Arial',
7
+ fontFamily: 'arial'
8
+ },
9
+ {
10
+ name: 'Arial Black',
11
+ fontFamily: 'arial black'
12
+ },
13
+ {
14
+ name: 'Baskerville',
15
+ fontFamily: 'baskerville'
16
+ },
17
+ {
18
+ name: 'Bodoni MT',
19
+ fontFamily: 'bodoni mt'
20
+ },
21
+ {
22
+ name: 'Brush Script MT',
23
+ fontFamily: 'brush script mt'
24
+ },
25
+ {
26
+ name: 'Calibri',
27
+ fontFamily: 'calibri'
28
+ },
29
+ {
30
+ name: 'Calisto MT',
31
+ fontFamily: 'calisto mt'
32
+ },
33
+ {
34
+ name: 'Cambria',
35
+ fontFamily: 'cambria'
36
+ },
37
+ {
38
+ name: 'Century Gothic',
39
+ fontFamily: 'century gothic'
40
+ },
41
+ {
42
+ name: 'Consolas',
43
+ fontFamily: 'consolas'
44
+ },
45
+ {
46
+ name: 'Comic Sans',
47
+ fontFamily: 'comic sans ms, comic sans'
48
+ },
49
+ {
50
+ name: 'Courier',
51
+ fontFamily: 'Courier'
52
+ },
53
+ {
54
+ name: 'Courier New',
55
+ fontFamily: 'courier new'
56
+ },
57
+ {
58
+ name: 'Cursive',
59
+ fontFamily: 'cursive'
60
+ },
61
+ {
62
+ name: 'Dejavu Sans',
63
+ fontFamily: 'dejavu sans'
64
+ },
65
+ {
66
+ name: 'Franklin Gothic',
67
+ fontFamily: 'franklin gothic'
68
+ },
69
+ {
70
+ name: 'Garamond',
71
+ fontFamily: 'garamond'
72
+ },
73
+ {
74
+ name: 'Georgia',
75
+ fontFamily: 'georgia'
76
+ },
77
+ {
78
+ name: 'Helvetica',
79
+ fontFamily: 'helvetica'
80
+ },
81
+ {
82
+ name: 'Impact',
83
+ fontFamily: 'impact'
84
+ },
85
+ {
86
+ name: 'Inter',
87
+ fontFamily: 'inter'
88
+ },
89
+ {
90
+ name: 'Monospace',
91
+ fontFamily: 'monospace'
92
+ },
93
+ {
94
+ name: 'Optima',
95
+ fontFamily: 'optima'
96
+ },
97
+ {
98
+ name: 'Segoe UI',
99
+ fontFamily: 'segoe ui'
100
+ },
101
+ {
102
+ name: 'Serif',
103
+ fontFamily: 'serif'
104
+ },
105
+ {
106
+ name: 'Tahoma',
107
+ fontFamily: 'tahoma'
108
+ },
109
+ {
110
+ name: 'Time New Roman',
111
+ fontFamily: 'times new roman'
112
+ },
113
+ {
114
+ name: 'Trebuchet MS',
115
+ fontFamily: 'trebuchet ms'
116
+ },
117
+ {
118
+ name: 'Verdana',
119
+ fontFamily: 'verdana'
120
+ },
121
+ ])
122
+
123
+ interface MDIIcons {
124
+ [key: string]: string
125
+ }
126
+ const mdiIcons = mdi as MDIIcons
127
+
128
+ interface ToolbarItemAttrs {
129
+ [key: string]: Function | any
130
+ }
131
+
132
+ interface ToolbarItemProps {
133
+ [key: string]: any
134
+ }
135
+
136
+ interface ToolbarItem {
137
+ name: string|number,
138
+ tooltip: string,
139
+ icon: string|ComputedRef<string>,
140
+ noI18n?: boolean,
141
+ enabled: boolean,
142
+ modelValue?: any,
143
+ section?: string,
144
+ group?: boolean,
145
+ props?: ToolbarItemProps,
146
+ attrs?: ToolbarItemAttrs,
147
+ children?: ToolbarItem[],
148
+ }
149
+
150
+ export interface ToolbarItems {
151
+ [key: string]: ToolbarItem
152
+ }
153
+
154
+ export interface ToolbarItemSections {
155
+ [key: string]: ToolbarItems
156
+ }
157
+
158
+ export function toolbarItems(
159
+ editor: any,
160
+ fontMeasure: string,
161
+ items: { list: Array<string>, exclude: boolean },
162
+ customHeadingLevels: Array<number>,
163
+ toolbarLinkButton: Ref,
164
+ ): ToolbarItemSections {
165
+ const headingLevels = ref([1, 2, 3, 4, 5, 6])
166
+ if (customHeadingLevels.length) {
167
+ customHeadingLevels.forEach(level => {
168
+ if (level <= 0 || level > 6) {
169
+ throw new Error('customHeadingLevels must be between 1 and 6')
170
+ }
171
+ })
172
+
173
+ headingLevels.value = customHeadingLevels
174
+ }
175
+
176
+ const fontSizes = [6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 32, 48, 64, 96]
177
+
178
+ const lineHeights = [1, 1.5, 2, 3, 4]
179
+
180
+ const allMenuItems: ToolbarItems = {
181
+ /**
182
+ * todo
183
+ *
184
+ * font color, backgroundcolor
185
+ * tables
186
+ * media (image, video)
187
+ * unsetmarks, clearnodes
188
+ */
189
+ heading: {
190
+ name: 'heading',
191
+ tooltip: 'style.heading',
192
+ icon: mdi.mdiFormatHeaderPound,
193
+ section: 'style',
194
+ modelValue: null,
195
+ enabled: true,
196
+ attrs: {
197
+ click: () => editor.value.chain().focus().setParagraph().run()
198
+ },
199
+ props: {
200
+ color: computed(() => editor.value.isActive('heading') ? 'primary' : ''),
201
+ },
202
+ children: headingLevels.value.map(level => {
203
+ return {
204
+ name: `H${level}`,
205
+ tooltip: `style.headings.h${level}`,
206
+ icon: mdiIcons[`mdiFormatHeader${level}`],
207
+ noI18n: true,
208
+ enabled: true,
209
+ props: {
210
+ color: computed(() => {
211
+ return editor.value.isActive('heading', { level }) ? 'primary' : ''
212
+ }),
213
+ },
214
+ attrs: {
215
+ click: () => editor.value.chain().focus().toggleHeading({ level }).run()
216
+ }
217
+ }
218
+ })
219
+ },
220
+ fontFamily: {
221
+ name: 'font-family',
222
+ tooltip: 'style.fontFamily',
223
+ icon: mdi.mdiFormatFont,
224
+ section: 'style',
225
+ modelValue: null,
226
+ enabled: true,
227
+ attrs: {
228
+ click: () => editor.value.chain().focus().unsetFontFamily().run()
229
+ },
230
+ children: fonts.value.map((font) => {
231
+ return {
232
+ name: font.name,
233
+ tooltip: '',
234
+ icon: '',
235
+ enabled: true,
236
+ noI18n: true,
237
+ props: {
238
+ color: computed(() => editor.value.isActive('textStyle', { fontFamily: font.fontFamily }) ? 'primary' : ''),
239
+ style: `font-family: ${font.fontFamily};`
240
+ },
241
+ attrs: {
242
+ click: () => editor.value.chain().focus().setFontFamily(font.fontFamily).run()
243
+ }
244
+ }
245
+ })
246
+ },
247
+ fontSize: {
248
+ name: 'font-size',
249
+ tooltip: 'style.fontSize',
250
+ icon: mdi.mdiFormatSize,
251
+ section: 'style',
252
+ modelValue: computed(() => editor.value.getAttributes('textStyle').fontSize || null),
253
+ enabled: true,
254
+ attrs: {
255
+ click: () => editor.value.chain().focus().unsetFontSize().run()
256
+ },
257
+ children: fontSizes.map((fontSize) => {
258
+ return {
259
+ name: `${fontSize}${fontMeasure}`,
260
+ tooltip: '',
261
+ icon: '',
262
+ enabled: true,
263
+ noI18n: true,
264
+ props: {
265
+ color: computed(() => editor.value.isActive('textStyle', { fontSizes: fontSize }) ? 'primary' : ''),
266
+ },
267
+ attrs: {
268
+ click: () => editor.value.chain().focus().setFontSize(`${fontSize}${fontMeasure}`).run()
269
+ }
270
+ }
271
+ })
272
+ },
273
+ lineHeight: {
274
+ name: 'line-height',
275
+ tooltip: 'style.lineHeight',
276
+ icon: mdi.mdiFormatLineHeight,
277
+ section: 'style',
278
+ modelValue: null,
279
+ enabled: true,
280
+ attrs: {
281
+ click: () => editor.value.chain().focus().unsetLineHeight().run()
282
+ },
283
+ children: lineHeights.map((lineHeight) => {
284
+ return {
285
+ name: lineHeight,
286
+ tooltip: '',
287
+ icon: '',
288
+ enabled: true,
289
+ noI18n: true,
290
+ props: {
291
+ color: computed(() => editor.value.isActive('textStyle', { lineHeights: lineHeight }) ? 'primary' : ''),
292
+ },
293
+ attrs: {
294
+ click: () => editor.value.chain().focus().setLineHeight(lineHeight).run()
295
+ }
296
+ }
297
+ })
298
+ },
299
+
300
+ bold: {
301
+ name: 'bold',
302
+ tooltip: 'format.bold',
303
+ icon: mdi.mdiFormatBold,
304
+ section: 'format',
305
+ enabled: true,
306
+ props: {
307
+ disabled: computed(() => !editor.value.can().chain().focus().toggleBold().run()),
308
+ color: computed(() => editor.value.isActive('bold') ? 'primary' : ''),
309
+ },
310
+ attrs: {
311
+ click: () => editor.value.chain().focus().toggleBold().run()
312
+ }
313
+ },
314
+ italic: {
315
+ name: 'italic',
316
+ tooltip: 'format.italic',
317
+ icon: mdi.mdiFormatItalic,
318
+ section: 'format',
319
+ enabled: true,
320
+ props: {
321
+ disabled: computed(() => !editor.value.can().chain().focus().toggleItalic().run()),
322
+ color: computed(() => editor.value.isActive('italic') ? 'primary' : ''),
323
+ },
324
+ attrs: {
325
+ click: () => editor.value.chain().focus().toggleItalic().run()
326
+ }
327
+ },
328
+ strike: {
329
+ name: 'strike',
330
+ tooltip: 'format.strike',
331
+ icon: mdi.mdiFormatStrikethroughVariant,
332
+ section: 'format',
333
+ enabled: true,
334
+ props: {
335
+ disabled: computed(() => !editor.value.can().chain().focus().toggleStrike().run()),
336
+ color: computed(() => editor.value.isActive('strike') ? 'primary' : ''),
337
+ },
338
+ attrs: {
339
+ click: () => editor.value.chain().focus().toggleStrike().run()
340
+ }
341
+ },
342
+ underline: {
343
+ name: 'underline',
344
+ tooltip: 'format.underline',
345
+ icon: mdi.mdiFormatUnderline,
346
+ section: 'format',
347
+ enabled: true,
348
+ props: {
349
+ disabled: computed(() => !editor.value.can().chain().focus().toggleUnderline().run()),
350
+ color: computed(() => editor.value.isActive('underline') ? 'primary' : ''),
351
+ },
352
+ attrs: {
353
+ click: () => editor.value.chain().focus().toggleUnderline().run()
354
+ }
355
+ },
356
+ highlight: {
357
+ name: 'highlight',
358
+ tooltip: 'format.highlight',
359
+ icon: mdi.mdiMarker,
360
+ section: 'format',
361
+ enabled: true,
362
+ props: {
363
+ disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
364
+ color: computed(() => editor.value.isActive('highlight') ? 'primary' : ''),
365
+ },
366
+ attrs: {
367
+ click: () => editor.value.chain().focus().toggleHighlight().run()
368
+ }
369
+ },
370
+ formatClear: {
371
+ name: 'format clear',
372
+ tooltip: 'format.formatClear',
373
+ icon: mdi.mdiFormatClear,
374
+ section: 'format',
375
+ enabled: true,
376
+ props: {
377
+ disabled: computed(() => !editor.value.can().chain().focus().unsetAllMarks().run()),
378
+ },
379
+ attrs: {
380
+ click: () => editor.value.chain().focus().unsetAllMarks().clearNodes().run()
381
+ }
382
+ },
383
+
384
+ code: {
385
+ name: 'code',
386
+ tooltip: 'format.code',
387
+ icon: mdi.mdiXml,
388
+ section: 'format_extra',
389
+ enabled: true,
390
+ props: {
391
+ disabled: computed(() => !editor.value.can().chain().focus().toggleCode().run()),
392
+ color: computed(() => editor.value.isActive('code') ? 'primary' : ''),
393
+ },
394
+ attrs: {
395
+ click: () => editor.value.chain().focus().toggleCode().run()
396
+ }
397
+ },
398
+ codeBlock: {
399
+ name: 'codeblock',
400
+ tooltip: 'format.codeblock',
401
+ icon: mdi.mdiCodeBlockTags,
402
+ section: 'format_extra',
403
+ enabled: true,
404
+ props: {
405
+ disabled: computed(() => !editor.value.can().chain().focus().toggleCodeBlock().run()),
406
+ color: computed(() => editor.value.isActive('codeBlock') ? 'primary' : ''),
407
+ },
408
+ attrs: {
409
+ click: () => editor.value.chain().focus().toggleCodeBlock().run()
410
+ }
411
+ },
412
+ blockquote: {
413
+ name: 'blockquote',
414
+ tooltip: 'format.blockquote',
415
+ icon: mdi.mdiCommentQuote,
416
+ section: 'format_extra',
417
+ enabled: true,
418
+ props: {
419
+ disabled: computed(() => !editor.value.can().chain().focus().toggleBlockquote().run()),
420
+ color: computed(() => editor.value.isActive('blockquote') ? 'primary' : ''),
421
+ },
422
+ attrs: {
423
+ click: () => editor.value.chain().focus().toggleBlockquote().run()
424
+ }
425
+ },
426
+
427
+ sup: {
428
+ name: 'sup',
429
+ tooltip: 'format.sup',
430
+ icon: mdi.mdiFormatSuperscript,
431
+ enabled: true,
432
+ props: {
433
+ disabled: computed(() => !editor.value.can().chain().focus().toggleSuperscript().run()),
434
+ color: computed(() => editor.value.isActive('superscript') ? 'primary' : ''),
435
+ },
436
+ attrs: {
437
+ click: () => editor.value.chain().focus().toggleSuperscript().run()
438
+ }
439
+ },
440
+ sub: {
441
+ name: 'sub',
442
+ tooltip: 'format.sub',
443
+ icon: mdi.mdiFormatSubscript,
444
+ enabled: true,
445
+ props: {
446
+ disabled: computed(() => !editor.value.can().chain().focus().toggleSubscript().run()),
447
+ color: computed(() => editor.value.isActive('subscript') ? 'primary' : ''),
448
+ },
449
+ attrs: {
450
+ click: () => editor.value.chain().focus().toggleSubscript().run()
451
+ }
452
+ },
453
+
454
+ alignment: {
455
+ name: 'alignment',
456
+ tooltip: 'alignment',
457
+ icon: '',
458
+ section: 'alignment',
459
+ enabled: true,
460
+ group: true,
461
+ children: [
462
+ {
463
+ name: 'alignments.left',
464
+ tooltip: 'alignments.left',
465
+ icon: mdi.mdiFormatAlignLeft,
466
+ enabled: true,
467
+ props: {
468
+ color: computed(() => editor.value.isActive('text-align', { align: 'left' }) ? 'primary' : ''),
469
+ },
470
+ attrs: {
471
+ click: () => editor.value.chain().focus().toggleTextAlign('left').run()
472
+ }
473
+ },
474
+ {
475
+ name: 'alignments.center',
476
+ tooltip: 'alignments.center',
477
+ icon: mdi.mdiFormatAlignCenter,
478
+ enabled: true,
479
+ props: {
480
+ color: computed(() => editor.value.isActive('text-align', { align: 'center' }) ? 'primary' : ''),
481
+ },
482
+ attrs: {
483
+ click: () => editor.value.chain().focus().toggleTextAlign('center').run()
484
+ }
485
+ },
486
+ {
487
+ name: 'alignments.right',
488
+ tooltip: 'alignments.right',
489
+ icon: mdi.mdiFormatAlignRight,
490
+ enabled: true,
491
+ props: {
492
+ color: computed(() => editor.value.isActive('text-align', { align: 'right' }) ? 'primary' : ''),
493
+ },
494
+ attrs: {
495
+ click: () => editor.value.chain().focus().toggleTextAlign('right').run()
496
+ }
497
+ },
498
+ {
499
+ name: 'alignments.justify',
500
+ tooltip: 'alignments.justify',
501
+ icon: mdi.mdiFormatAlignJustify,
502
+ enabled: true,
503
+ props: {
504
+ color: computed(() => editor.value.isActive('text-align', { align: 'justify' }) ? 'primary' : ''),
505
+ },
506
+ attrs: {
507
+ click: () => editor.value.chain().focus().toggleTextAlign('justify').run()
508
+ }
509
+ },
510
+ ]
511
+ },
512
+
513
+ list: {
514
+ name: 'list',
515
+ tooltip: 'list',
516
+ icon: mdi.mdiFormatListGroup,
517
+ section: 'list',
518
+ enabled: true,
519
+ group: true,
520
+ children: [
521
+ {
522
+ name: 'lists.bullet',
523
+ tooltip: 'lists.bullet',
524
+ icon: mdi.mdiFormatListBulleted,
525
+ enabled: true,
526
+ props: {
527
+ color: computed(() => editor.value.isActive('bulletList') ? 'primary' : ''),
528
+ },
529
+ attrs: {
530
+ click: () => editor.value.chain().focus().toggleBulletList().run()
531
+ }
532
+ },
533
+ {
534
+ name: 'lists.numbered',
535
+ tooltip: 'lists.numbered',
536
+ icon: mdi.mdiFormatListNumbered,
537
+ enabled: true,
538
+ props: {
539
+ color: computed(() => editor.value.isActive('orderedList') ? 'primary' : ''),
540
+ },
541
+ attrs: {
542
+ click: () => editor.value.chain().focus().toggleOrderedList().run()
543
+ }
544
+ },
545
+ {
546
+ name: 'lists.task',
547
+ tooltip: 'lists.task',
548
+ icon: mdi.mdiFormatListChecks,
549
+ enabled: true,
550
+ props: {
551
+ color: computed(() => editor.value.isActive('taskList') ? 'primary' : ''),
552
+ },
553
+ attrs: {
554
+ click: () => editor.value.chain().focus().toggleTaskList().run()
555
+ }
556
+ },
557
+ {
558
+ name: 'lists.indent',
559
+ tooltip: 'lists.indent',
560
+ icon: mdi.mdiFormatIndentIncrease,
561
+ enabled: true,
562
+ props: {
563
+ disabled: computed(() => !editor.value.can().sinkListItem('listItem')),
564
+ active: false,
565
+ },
566
+ attrs: {
567
+ click: () => editor.value.chain().focus().sinkListItem('listItem').run()
568
+ }
569
+ },
570
+ {
571
+ name: 'lists.outdent',
572
+ tooltip: 'lists.outdent',
573
+ icon: mdi.mdiFormatIndentDecrease,
574
+ enabled: true,
575
+ props: {
576
+ disabled: computed(() => !editor.value.can().liftListItem('listItem')),
577
+ active: false,
578
+ },
579
+ attrs: {
580
+ click: () => editor.value.chain().focus().liftListItem('listItem').run()
581
+ }
582
+ },
583
+ ]
584
+ },
585
+
586
+ link: {
587
+ name: 'format.link',
588
+ tooltip: 'format.link',
589
+ icon: computed(() => editor.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
590
+ section: 'media',
591
+ enabled: true,
592
+ props: {
593
+ color: computed(() => editor.value.isActive('link') ? 'primary' : ''),
594
+ disabled: computed(() => editor.value.isActive('code') || editor.value.isActive('codeBlock')),
595
+ },
596
+ attrs: {
597
+ click: computed(() => {
598
+ return editor.value.isActive('link')
599
+ ? editor.value.chain().focus().unsetLink().run
600
+ : toolbarLinkButton.value?.open
601
+ })
602
+ }
603
+ },
604
+
605
+ undo: {
606
+ name: 'undo',
607
+ tooltip: 'action.undo',
608
+ icon: mdi.mdiUndo,
609
+ section: 'actions',
610
+ enabled: true,
611
+ props: {
612
+ disabled: computed(() => !editor.value.can().chain().focus().undo().run()),
613
+ },
614
+ attrs: {
615
+ click: () => editor.value.chain().focus().undo().run()
616
+ }
617
+ },
618
+ redo: {
619
+ name: 'redo',
620
+ tooltip: 'action.redo',
621
+ icon: mdi.mdiRedo,
622
+ section: 'actions',
623
+ enabled: true,
624
+ props: {
625
+ disabled: computed(() => !editor.value.can().chain().focus().redo().run()),
626
+ },
627
+ attrs: {
628
+ click: () => editor.value.chain().focus().redo().run()
629
+ }
630
+ },
631
+
632
+ line: {
633
+ name: 'line',
634
+ tooltip: 'format.line',
635
+ icon: mdi.mdiMinus,
636
+ section: 'misc',
637
+ enabled: true,
638
+ props: {},
639
+ attrs: {
640
+ click: () => editor.value.chain().focus().setHorizontalRule().run()
641
+ }
642
+ },
643
+ break: {
644
+ name: 'break',
645
+ tooltip: 'format.break',
646
+ icon: mdi.mdiFormatPageBreak,
647
+ section: 'misc',
648
+ enabled: true,
649
+ props: {},
650
+ attrs: {
651
+ click: () => editor.value.chain().focus().setHardBreak().run()
652
+ }
653
+ },
654
+ }
655
+
656
+
657
+
658
+ const pluginsList = Object.keys(allMenuItems)
659
+
660
+ if (items.list.length) {
661
+ items.list.forEach(item => {
662
+ if (!pluginsList.includes(item)) {
663
+ throw new Error(`Unknown plugin name: ${item}! Supported plugins: ${pluginsList.join(', ')}`)
664
+ }
665
+ })
666
+ }
667
+
668
+ const sections = {}
669
+ const toolbarItems: { [key: string]: ToolbarItems } = {}
670
+ pluginsList.forEach(key => {
671
+ const item = allMenuItems[key]
672
+
673
+ if (items.list.length) {
674
+ item.enabled = items.list.includes(key)
675
+ if (items.exclude) {
676
+ item.enabled = !item.enabled
677
+ }
678
+ }
679
+ const section = item.section ?? 'misc'
680
+ if (typeof toolbarItems[section] === 'undefined') {
681
+ sections[section] = 0
682
+ toolbarItems[section] = {}
683
+ }
684
+ toolbarItems[section][key] = allMenuItems[key]
685
+ if (allMenuItems[key].enabled) {
686
+ sections[section]++
687
+ }
688
+ })
689
+
690
+ Object.keys(sections).forEach(key => {
691
+ if (sections[key] === 0) {
692
+ delete toolbarItems[key]
693
+ }
694
+ })
695
+
696
+ return toolbarItems
697
+ }