tiptapify 0.0.10 → 0.0.12

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.
Files changed (107) hide show
  1. package/README.md +7 -3
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/tiptapify.mjs +18524 -17801
  4. package/dist/tiptapify.umd.js +77 -38
  5. package/index.d.ts +2 -2
  6. package/package.json +41 -40
  7. package/src/components/MenuBubble.vue +8 -8
  8. package/src/components/Tiptapify.vue +5 -6
  9. package/src/components/Toolbar/Group.vue +2 -2
  10. package/src/components/Toolbar/GroupBtn.vue +12 -9
  11. package/src/components/Toolbar/GroupDropdown.vue +5 -19
  12. package/src/components/Toolbar/Index.vue +13 -9
  13. package/src/components/Toolbar/Items.vue +5 -8
  14. package/src/components/Toolbar/Toggle.vue +3 -5
  15. package/src/components/Toolbar/defaultExtensionComponents.ts +34 -13
  16. package/src/components/Toolbar/items.ts +53 -70
  17. package/src/components/UI/BtnIcon.vue +24 -0
  18. package/src/components/UI/{Dialog.vue → TiptapifyDialog.vue} +4 -3
  19. package/src/components/editorExtensions.ts +17 -2
  20. package/src/components/index.ts +8 -2
  21. package/src/composables/Toolbar/Actions/useRedo.ts +23 -0
  22. package/src/composables/Toolbar/Actions/useUndo.ts +23 -0
  23. package/src/composables/Toolbar/Alignment/useAlignmentCenter.ts +24 -0
  24. package/src/composables/Toolbar/Alignment/useAlignmentJustify.ts +24 -0
  25. package/src/composables/Toolbar/Alignment/useAlignmentLeft.ts +24 -0
  26. package/src/composables/Toolbar/Alignment/useAlignmentRight.ts +24 -0
  27. package/src/composables/Toolbar/Format/useBold.ts +24 -0
  28. package/src/composables/Toolbar/Format/useItalic.ts +24 -0
  29. package/src/composables/Toolbar/Format/useStrike.ts +24 -0
  30. package/src/composables/Toolbar/Format/useUnderline.ts +24 -0
  31. package/src/composables/Toolbar/FormatExtra/useBlockquote.ts +24 -0
  32. package/src/composables/Toolbar/FormatExtra/useCode.ts +24 -0
  33. package/src/composables/Toolbar/FormatExtra/useCodeBlock.ts +24 -0
  34. package/src/composables/Toolbar/FormatExtra/useSub.ts +24 -0
  35. package/src/composables/Toolbar/FormatExtra/useSup.ts +24 -0
  36. package/src/composables/Toolbar/List/useBullet.ts +23 -0
  37. package/src/composables/Toolbar/List/useIndent.ts +24 -0
  38. package/src/composables/Toolbar/List/useNumbered.ts +23 -0
  39. package/src/composables/Toolbar/List/useOutdent.ts +24 -0
  40. package/src/composables/Toolbar/List/useTask.ts +23 -0
  41. package/src/composables/Toolbar/Media/useImage.ts +24 -0
  42. package/src/composables/Toolbar/Media/useLink.ts +24 -0
  43. package/src/composables/Toolbar/Media/useTable.ts +188 -0
  44. package/src/composables/Toolbar/Misc/useBreak.ts +21 -0
  45. package/src/composables/Toolbar/Misc/useFormatClear.ts +23 -0
  46. package/src/composables/Toolbar/Misc/useInvisibleCharacters.ts +23 -0
  47. package/src/composables/Toolbar/Misc/useLine.ts +21 -0
  48. package/src/composables/Toolbar/Misc/usePreview.ts +20 -0
  49. package/src/composables/Toolbar/Misc/useSource.ts +21 -0
  50. package/src/composables/Toolbar/Style/useColor.ts +36 -0
  51. package/src/composables/Toolbar/Style/useFontFamily.ts +49 -0
  52. package/src/composables/Toolbar/Style/useFontSize.ts +50 -0
  53. package/src/composables/Toolbar/Style/useHeading.ts +64 -0
  54. package/src/composables/Toolbar/Style/useHighlight.ts +36 -0
  55. package/src/composables/Toolbar/Style/useLineHeight.ts +49 -0
  56. package/src/composables/Toolbar/useActionsItems.ts +9 -0
  57. package/src/composables/Toolbar/useAlignmentItems.ts +13 -0
  58. package/src/composables/Toolbar/useFormatExtraItems.ts +15 -0
  59. package/src/composables/Toolbar/useFormatItems.ts +13 -0
  60. package/src/composables/Toolbar/useListItems.ts +15 -0
  61. package/src/composables/Toolbar/useMediaItems.ts +11 -0
  62. package/src/composables/Toolbar/useMiscItems.ts +17 -0
  63. package/src/composables/Toolbar/useStyleItems.ts +17 -0
  64. package/src/{components/Toolbar/fonts.ts → constants/style.ts} +21 -0
  65. package/src/extensions/components/FontFamily.vue +82 -0
  66. package/src/extensions/components/FontSize.vue +83 -0
  67. package/src/extensions/components/ImageDialog.vue +7 -3
  68. package/src/extensions/components/LineHeight.vue +82 -0
  69. package/src/extensions/components/LinkDialog.vue +27 -7
  70. package/src/extensions/components/PreviewDialog.vue +11 -4
  71. package/src/extensions/components/ShowSourceDialog.vue +10 -6
  72. package/src/extensions/components/StyleColor.vue +2 -2
  73. package/src/extensions/components/slashCommands/CommandsList.vue +1 -4
  74. package/src/extensions/image.ts +2 -1
  75. package/src/extensions/link.ts +10 -1
  76. package/src/extensions/preview.ts +2 -1
  77. package/src/extensions/slash-commands.ts +1 -1
  78. package/src/extensions/view-source.ts +2 -1
  79. package/src/i18n/locales/ch.json +84 -82
  80. package/src/i18n/locales/cz.json +32 -30
  81. package/src/i18n/locales/de.json +28 -26
  82. package/src/i18n/locales/en.json +3 -1
  83. package/src/i18n/locales/es.json +30 -28
  84. package/src/i18n/locales/fr.json +30 -28
  85. package/src/i18n/locales/it.json +32 -30
  86. package/src/i18n/locales/la.json +61 -59
  87. package/src/i18n/locales/lt.json +38 -36
  88. package/src/i18n/locales/nl.json +31 -29
  89. package/src/i18n/locales/pl.json +32 -30
  90. package/src/i18n/locales/pt.json +29 -27
  91. package/src/i18n/locales/ru.json +3 -1
  92. package/src/i18n/locales/se.json +30 -28
  93. package/src/i18n/locales/ua.json +3 -1
  94. package/src/index.ts +3 -1
  95. package/src/types/extensionComponents.ts +22 -0
  96. package/src/types/toolbarItems.ts +43 -0
  97. package/src/types/toolbarSections.ts +11 -0
  98. package/src/components/Toolbar/items/actions.ts +0 -32
  99. package/src/components/Toolbar/items/alignment.ts +0 -60
  100. package/src/components/Toolbar/items/format.ts +0 -60
  101. package/src/components/Toolbar/items/formatExtra.ts +0 -73
  102. package/src/components/Toolbar/items/list.ts +0 -70
  103. package/src/components/Toolbar/items/media.ts +0 -211
  104. package/src/components/Toolbar/items/misc.ts +0 -59
  105. package/src/components/Toolbar/items/style.ts +0 -204
  106. package/src/types/overridable-extensions.ts +0 -6
  107. /package/src/{components → extensions/components}/CodeBlockComponent.vue +0 -0
@@ -0,0 +1,64 @@
1
+ import * as mdi from "@mdi/js";
2
+ import { Level } from "@tiptap/extension-heading";
3
+ import { Editor } from "@tiptap/vue-3";
4
+ import { headingLevels, setHeadingLevels } from "@tiptapify/constants/style";
5
+ import { computed, inject, Ref } from "vue";
6
+ import { useI18n } from "vue-i18n";
7
+
8
+ interface MDIIcons {
9
+ [key: string]: string
10
+ }
11
+ const mdiIcons = mdi as MDIIcons
12
+
13
+ export function useHeading(customHeadingLevels: Array<number> = []) {
14
+ const { t } = useI18n();
15
+
16
+ setHeadingLevels(customHeadingLevels)
17
+
18
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
19
+
20
+ return {
21
+ name: 'heading',
22
+ tooltip: computed(() => t('style.heading')),
23
+ icon: `mdiSvg:${mdi.mdiFormatHeaderPound}`,
24
+ modelValue: null,
25
+ enabled: true,
26
+ props: {
27
+ color: computed(() => editor.value.isActive('heading') || editor.value.isActive('paragraph') ? 'primary' : ''),
28
+ },
29
+ children: [
30
+ {
31
+ name: 'paragraph',
32
+ tooltip: computed(() => t('style.paragraph')),
33
+ // icon: mdiIcons['mdiFormatParagraph'],
34
+ icon: `mdiSvg:${mdiIcons['mdiFormatParagraph']}`,
35
+ noI18n: true,
36
+ enabled: true,
37
+ props: {
38
+ color: computed(() => editor.value.isActive('paragraph') ? 'primary' : ''),
39
+ },
40
+ attrs: {
41
+ click: () => editor.value.chain().focus().setParagraph().run()
42
+ }
43
+ }
44
+ ].concat(
45
+ headingLevels.value.map(level => {
46
+ const headingLevel: Level = level as Level
47
+ return {
48
+ name: `H${level}`,
49
+ tooltip: computed(() => t(`style.headings.h${level}`)),
50
+ // icon: mdiIcons[`mdiFormatHeader${level}`],
51
+ icon: `mdiSvg:${mdiIcons[`mdiFormatHeader${level}`]}`,
52
+ noI18n: true,
53
+ enabled: true,
54
+ props: {
55
+ color: computed(() => editor.value.isActive('heading', {level: level}) ? 'primary' : ''),
56
+ },
57
+ attrs: {
58
+ click: () => editor.value.chain().focus().toggleHeading({level: headingLevel}).run()
59
+ }
60
+ }
61
+ })
62
+ )
63
+ }
64
+ }
@@ -0,0 +1,36 @@
1
+ import * as mdi from "@mdi/js";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import StyleColor from "@tiptapify/extensions/components/StyleColor.vue";
4
+ import { computed, inject, markRaw, Ref } from "vue";
5
+ import { useI18n } from "vue-i18n";
6
+
7
+ export function useHighlight(theme: any) {
8
+ const { t } = useI18n();
9
+
10
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
11
+
12
+ return {
13
+ name: 'highlight',
14
+ tooltip: computed(() => t('style.color.highlight')),
15
+ icon: `mdiSvg:${mdi.mdiFormatColorFill}`,
16
+ icon2: `mdiSvg:${mdi.mdiColorHelper}`,
17
+ enabled: true,
18
+ props: {
19
+ disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
20
+ },
21
+ icon2Props: {
22
+ disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
23
+ color: computed(() => {
24
+ const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
25
+ return editor.value.getAttributes('highlight').color || defaultColor
26
+ }),
27
+ style: 'filter: drop-shadow(rgba(0, 0, 0, .75) 1px 1px 2px);'
28
+ },
29
+ component: markRaw(StyleColor),
30
+ componentProps: {
31
+ fontColor: false,
32
+ backgroundColor: true,
33
+ color: computed(() => editor.value.getAttributes('highlight').color || ''),
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,49 @@
1
+ import * as mdi from "@mdi/js";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import { lineHeights } from "@tiptapify/constants/style";
4
+ import LineHeight from "@tiptapify/extensions/components/LineHeight.vue";
5
+ import { computed, inject, markRaw, Ref } from "vue";
6
+ import { useI18n } from "vue-i18n";
7
+
8
+ export function useLineHeight() {
9
+ const { t } = useI18n();
10
+
11
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
12
+
13
+ return {
14
+ name: 'line-height',
15
+ tooltip: computed(() => t('style.lineHeight')),
16
+ icon: `mdiSvg:${mdi.mdiFormatLineHeight}`,
17
+ modelValue: null,
18
+ enabled: true,
19
+ props: {
20
+ disabled: computed(() => !editor.value.can().chain().focus().unsetLineHeight().run()),
21
+ color: computed(() => {
22
+ let color = ''
23
+ for (const height of lineHeights) {
24
+ if (editor.value.isActive('textStyle', { lineHeight: height.toString() })) {
25
+ color = 'primary'
26
+ break;
27
+ }
28
+ }
29
+
30
+ return color
31
+ }),
32
+ },
33
+ component: markRaw(LineHeight),
34
+ componentProps: {
35
+ lineHeights,
36
+ lineHeight: computed(() => {
37
+ let lineHeight = null
38
+ for (const height of lineHeights) {
39
+ if (editor.value.isActive('textStyle', { lineHeight: height.toString() })) {
40
+ lineHeight = height
41
+ break;
42
+ }
43
+ }
44
+
45
+ return lineHeight
46
+ }),
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,9 @@
1
+ import { useRedo } from "@tiptapify/composables/Toolbar/Actions/useRedo";
2
+ import { useUndo } from "@tiptapify/composables/Toolbar/Actions/useUndo";
3
+
4
+ export function useActionsItems() {
5
+ return {
6
+ undo: useUndo(),
7
+ redo: useRedo()
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ import { useAlignmentCenter } from "@tiptapify/composables/Toolbar/Alignment/useAlignmentCenter";
2
+ import { useAlignmentJustify } from "@tiptapify/composables/Toolbar/Alignment/useAlignmentJustify";
3
+ import { useAlignmentLeft } from "@tiptapify/composables/Toolbar/Alignment/useAlignmentLeft";
4
+ import { useAlignmentRight } from "@tiptapify/composables/Toolbar/Alignment/useAlignmentRight";
5
+
6
+ export function useAlignmentItems() {
7
+ return {
8
+ alignmentLeft: useAlignmentLeft(),
9
+ alignmentCenter: useAlignmentCenter(),
10
+ alignmentRight: useAlignmentRight(),
11
+ alignmentJustify: useAlignmentJustify()
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import { useBlockquote } from "@tiptapify/composables/Toolbar/FormatExtra/useBlockquote";
2
+ import { useCode } from "@tiptapify/composables/Toolbar/FormatExtra/useCode";
3
+ import { useCodeBlock } from "@tiptapify/composables/Toolbar/FormatExtra/useCodeBlock";
4
+ import { useSub } from "@tiptapify/composables/Toolbar/FormatExtra/useSub";
5
+ import { useSup } from "@tiptapify/composables/Toolbar/FormatExtra/useSup";
6
+
7
+ export function useFormatExtraItems() {
8
+ return {
9
+ sup: useSup(),
10
+ sub: useSub(),
11
+ code: useCode(),
12
+ codeBlock: useCodeBlock(),
13
+ blockquote: useBlockquote()
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ import { useBold } from "@tiptapify/composables/Toolbar/Format/useBold";
2
+ import { useItalic } from "@tiptapify/composables/Toolbar/Format/useItalic";
3
+ import { useStrike } from "@tiptapify/composables/Toolbar/Format/useStrike";
4
+ import { useUnderline } from "@tiptapify/composables/Toolbar/Format/useUnderline";
5
+
6
+ export function useFormatItems() {
7
+ return {
8
+ bold: useBold(),
9
+ italic: useItalic(),
10
+ underline: useUnderline(),
11
+ strike: useStrike()
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import { useBullet } from "@tiptapify/composables/Toolbar/List/useBullet";
2
+ import { useIndent } from "@tiptapify/composables/Toolbar/List/useIndent";
3
+ import { useNumbered } from "@tiptapify/composables/Toolbar/List/useNumbered";
4
+ import { useOutdent } from "@tiptapify/composables/Toolbar/List/useOutdent";
5
+ import { useTask } from "@tiptapify/composables/Toolbar/List/useTask";
6
+
7
+ export function useListItems() {
8
+ return {
9
+ listBullet: useBullet(),
10
+ listNumbered: useNumbered(),
11
+ listTask: useTask(),
12
+ listIndent: useIndent(),
13
+ listOutdent: useOutdent()
14
+ }
15
+ }
@@ -0,0 +1,11 @@
1
+ import { useImage } from "@tiptapify/composables/Toolbar/Media/useImage";
2
+ import { useLink } from "@tiptapify/composables/Toolbar/Media/useLink";
3
+ import { useTable } from "@tiptapify/composables/Toolbar/Media/useTable";
4
+
5
+ export function useMediaItems() {
6
+ return {
7
+ link: useLink(),
8
+ image: useImage(),
9
+ table: useTable()
10
+ }
11
+ }
@@ -0,0 +1,17 @@
1
+ import { useBreak } from "@tiptapify/composables/Toolbar/Misc/useBreak";
2
+ import { useFormatClear } from "@tiptapify/composables/Toolbar/Misc/useFormatClear";
3
+ import { useInvisibleCharacters } from "@tiptapify/composables/Toolbar/Misc/useInvisibleCharacters";
4
+ import { useLine } from "@tiptapify/composables/Toolbar/Misc/useLine";
5
+ import { usePreview } from "@tiptapify/composables/Toolbar/Misc/usePreview";
6
+ import { useSource } from "@tiptapify/composables/Toolbar/Misc/useSource";
7
+
8
+ export function useMiscItems() {
9
+ return {
10
+ line: useLine(),
11
+ break: useBreak(),
12
+ source: useSource(),
13
+ preview: usePreview(),
14
+ formatClear: useFormatClear(),
15
+ invisibleCharacters: useInvisibleCharacters(),
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ import { useColor } from "@tiptapify/composables/Toolbar/Style/useColor";
2
+ import { useFontFamily } from "@tiptapify/composables/Toolbar/Style/useFontFamily";
3
+ import { useFontSize } from "@tiptapify/composables/Toolbar/Style/useFontSize";
4
+ import { useHeading } from "@tiptapify/composables/Toolbar/Style/useHeading";
5
+ import { useHighlight } from "@tiptapify/composables/Toolbar/Style/useHighlight";
6
+ import { useLineHeight } from "@tiptapify/composables/Toolbar/Style/useLineHeight";
7
+
8
+ export function useStyleItems(theme: any, fontMeasure: string, customHeadingLevels: Array<number> = []) {
9
+ return {
10
+ heading: useHeading(customHeadingLevels),
11
+ fontFamily: useFontFamily(),
12
+ fontSize: useFontSize(fontMeasure),
13
+ lineHeight: useLineHeight(),
14
+ highlight: useHighlight(theme),
15
+ color: useColor(theme)
16
+ }
17
+ }
@@ -1,3 +1,24 @@
1
+ import { ref } from "vue";
2
+
3
+ export const defaultFontSize = 12
4
+ export const fontSizes = [6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 32, 48, 64, 96]
5
+
6
+ export const defaultLineHeight = 1
7
+ export const lineHeights = [1, 1.5, 2, 3, 4]
8
+
9
+ export const headingLevels = ref([1, 2, 3, 4, 5, 6])
10
+ export function setHeadingLevels(customHeadingLevels: number[]) {
11
+ if (customHeadingLevels.length) {
12
+ customHeadingLevels.forEach(level => {
13
+ if (level < 1 || level > 6) {
14
+ throw new Error('customHeadingLevels must be between 1 and 6')
15
+ }
16
+ })
17
+
18
+ headingLevels.value = customHeadingLevels
19
+ }
20
+ }
21
+
1
22
  export const fonts = [
2
23
  {
3
24
  name: 'Arial',
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+
3
+ import { Editor } from "@tiptap/vue-3";
4
+
5
+ import { computed, inject, Ref, ref } from 'vue'
6
+ import { useI18n } from "vue-i18n";
7
+
8
+ const props = defineProps({
9
+ fonts: { type: Array<{ name: string, fontFamily: string }>, default: [] },
10
+ fontFamily: { type: String, default: '' },
11
+ })
12
+
13
+ const { t } = useI18n();
14
+
15
+ const emit = defineEmits(['close'])
16
+
17
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
18
+
19
+ const initialFontFamily = ref(computed(() => props.fontFamily).value)
20
+
21
+ const fontSelected = ref<boolean>(false)
22
+
23
+ function hoverFontFamily(font: string) {
24
+ fontSelected.value = false
25
+
26
+ editor.value.chain().focus().setFontFamily(font).run()
27
+ }
28
+
29
+ function resetFontFamily() {
30
+ if (fontSelected.value) {
31
+ return
32
+ }
33
+
34
+ initialFontFamily.value
35
+ ? editor.value.chain().focus().setFontFamily(initialFontFamily.value).run()
36
+ : editor.value.chain().focus().unsetFontFamily().run()
37
+ }
38
+
39
+ function clearFontFamily() {
40
+ editor.value.chain().focus().unsetFontFamily().run()
41
+ emit('close')
42
+ }
43
+
44
+ function setFontFamily() {
45
+ fontSelected.value = true
46
+
47
+ emit('close')
48
+ }
49
+
50
+ function isFontFamilyActive(fontFamily: string): boolean {
51
+ return editor.value.isActive('textStyle', { fontFamily }) || fontFamily === initialFontFamily.value
52
+ }
53
+ </script>
54
+
55
+ <template>
56
+ <VList class="tiptapify-font-family-list">
57
+ <VListItem :disabled="fontFamily === ''" density="compact" @click="clearFontFamily">
58
+ <VListItemTitle class="font-italic text-grey-darken-1">
59
+ {{ t('defaultValue') }}
60
+ </VListItemTitle>
61
+ </VListItem>
62
+ <VListItem
63
+ v-for="font in fonts"
64
+ :active="isFontFamilyActive(font.fontFamily)"
65
+ :color="font.fontFamily === initialFontFamily ? 'primary' : ''"
66
+ density="compact"
67
+ @click="setFontFamily"
68
+ @mouseover="hoverFontFamily(font.fontFamily)"
69
+ @mouseleave="resetFontFamily"
70
+ >
71
+ <VListItemTitle>
72
+ {{ font.name }}
73
+ </VListItemTitle>
74
+ </VListItem>
75
+ </VList>
76
+ </template>
77
+
78
+ <style lang="scss" scoped>
79
+ .tiptapify-font-family-list {
80
+ max-height: 390px;
81
+ }
82
+ </style>
@@ -0,0 +1,83 @@
1
+ <script setup lang="ts">
2
+
3
+ import { Editor } from "@tiptap/vue-3";
4
+
5
+ import { computed, inject, Ref, ref } from 'vue'
6
+ import { useI18n } from "vue-i18n";
7
+
8
+ const props = defineProps({
9
+ sizes: { type: Array<number>, default: [] },
10
+ measure: { type: String, default: 'px' },
11
+ fontSize: { type: Number, default () { return null } },
12
+ })
13
+
14
+ const { t } = useI18n();
15
+
16
+ const emit = defineEmits(['close'])
17
+
18
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
19
+
20
+ const initialFontSize = ref(computed(() => props.fontSize).value)
21
+
22
+ const fontSizeSelected = ref<boolean>(false)
23
+
24
+ function hoverFontSize(fontSize: number) {
25
+ fontSizeSelected.value = false
26
+
27
+ editor.value.chain().focus().setFontSize(`${fontSize}${props.measure}`).run()
28
+ }
29
+
30
+ function resetFontSize() {
31
+ if (fontSizeSelected.value) {
32
+ return
33
+ }
34
+
35
+ initialFontSize.value
36
+ ? editor.value.chain().focus().setFontSize(`${initialFontSize.value}${props.measure}`).run()
37
+ : editor.value.chain().focus().unsetFontSize().run()
38
+ }
39
+
40
+ function clearFontSize() {
41
+ editor.value.chain().focus().unsetFontSize().run()
42
+ emit('close')
43
+ }
44
+
45
+ function setFontSize() {
46
+ fontSizeSelected.value = true
47
+
48
+ emit('close')
49
+ }
50
+
51
+ function isFontSizeActive(fontSize: number): boolean {
52
+ return editor.value.isActive('textStyle', { fontSize: `${fontSize}${props.measure}` }) || fontSize === initialFontSize.value
53
+ }
54
+ </script>
55
+
56
+ <template>
57
+ <VList class="tiptapify-font-size-list">
58
+ <VListItem :disabled="fontSize === null" density="compact" @click="clearFontSize">
59
+ <VListItemTitle class="font-italic text-grey-darken-1">
60
+ {{ t('defaultValue') }}
61
+ </VListItemTitle>
62
+ </VListItem>
63
+ <VListItem
64
+ v-for="size in sizes"
65
+ :active="isFontSizeActive(size)"
66
+ :color="size === initialFontSize ? 'primary' : ''"
67
+ density="compact"
68
+ @click="setFontSize"
69
+ @mouseover="hoverFontSize(size)"
70
+ @mouseleave="resetFontSize"
71
+ >
72
+ <VListItemTitle>
73
+ {{ size }}{{ measure}}
74
+ </VListItemTitle>
75
+ </VListItem>
76
+ </VList>
77
+ </template>
78
+
79
+ <style lang="scss" scoped>
80
+ .tiptapify-font-size-list {
81
+ max-height: 390px;
82
+ }
83
+ </style>
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
 
3
3
  import { Editor } from "@tiptap/vue-3";
4
- import Dialog from "@tiptapify/components/UI/Dialog.vue";
4
+ import TiptapifyDialog from "@tiptapify/components/UI/TiptapifyDialog.vue";
5
5
 
6
6
  import { useI18n } from 'vue-i18n'
7
7
  import { computed, inject, onMounted, onUnmounted, Ref, ref } from 'vue'
@@ -66,6 +66,10 @@ function close() {
66
66
  }
67
67
 
68
68
  const showTiptapifyImage = (event: CustomEvent) => {
69
+ if (event.detail.editorId !== editor.value.instanceId) {
70
+ return
71
+ }
72
+
69
73
  attrs.value.src = event.detail.image?.src
70
74
  attrs.value.alt = event.detail.image?.alt
71
75
  attrs.value.width = event.detail.image?.width
@@ -84,7 +88,7 @@ onUnmounted(() => {
84
88
  </script>
85
89
 
86
90
  <template>
87
- <Dialog ref="dialog" module="image" :max-width="800">
91
+ <TiptapifyDialog ref="dialog" module="image" :max-width="800">
88
92
  <template #content>
89
93
  <VCardText>
90
94
  <VRow>
@@ -126,5 +130,5 @@ onUnmounted(() => {
126
130
  </VRow>
127
131
  </VCardActions>
128
132
  </template>
129
- </Dialog>
133
+ </TiptapifyDialog>
130
134
  </template>
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+
3
+ import { Editor } from "@tiptap/vue-3";
4
+
5
+ import { computed, inject, Ref, ref } from 'vue'
6
+ import { useI18n } from "vue-i18n";
7
+
8
+ const props = defineProps({
9
+ lineHeights: { type: Array<number>, default () { return [] } },
10
+ lineHeight: { type: Number, default () { return null } },
11
+ })
12
+
13
+ const { t } = useI18n();
14
+
15
+ const emit = defineEmits(['close'])
16
+
17
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
18
+
19
+ const initialLineHeight = ref(computed(() => props.lineHeight).value)
20
+
21
+ const lineHeightSelected = ref<boolean>(false)
22
+
23
+ function hoverLineHeight(lineHeight: number) {
24
+ lineHeightSelected.value = false
25
+
26
+ editor.value.chain().focus().setLineHeight(lineHeight.toString()).run()
27
+ }
28
+
29
+ function resetLineHeight() {
30
+ if (lineHeightSelected.value) {
31
+ return
32
+ }
33
+
34
+ initialLineHeight.value
35
+ ? editor.value.chain().focus().setLineHeight(initialLineHeight.value.toString()).run()
36
+ : editor.value.chain().focus().unsetLineHeight().run()
37
+ }
38
+
39
+ function clearLineHeight() {
40
+ editor.value.chain().focus().unsetLineHeight().run()
41
+ emit('close')
42
+ }
43
+
44
+ function setLineHeight() {
45
+ lineHeightSelected.value = true
46
+
47
+ emit('close')
48
+ }
49
+
50
+ function isLineHeightActive(lineHeight: number): boolean {
51
+ return editor.value.isActive('textStyle', { lineHeight }) || lineHeight === initialLineHeight.value
52
+ }
53
+ </script>
54
+
55
+ <template>
56
+ <VList class="tiptapify-line-height-list">
57
+ <VListItem :disabled="lineHeight === null" density="compact" @click="clearLineHeight">
58
+ <VListItemTitle class="font-italic text-grey-darken-1">
59
+ {{ t('defaultValue') }}
60
+ </VListItemTitle>
61
+ </VListItem>
62
+ <VListItem
63
+ v-for="lineHeight in lineHeights"
64
+ :active="isLineHeightActive(lineHeight)"
65
+ :color="lineHeight === initialLineHeight ? 'primary' : ''"
66
+ density="compact"
67
+ @click="setLineHeight"
68
+ @mouseover="hoverLineHeight(lineHeight)"
69
+ @mouseleave="resetLineHeight"
70
+ >
71
+ <VListItemTitle>
72
+ {{ lineHeight }}
73
+ </VListItemTitle>
74
+ </VListItem>
75
+ </VList>
76
+ </template>
77
+
78
+ <style lang="scss" scoped>
79
+ .tiptapify-line-height-list {
80
+ max-height: 390px;
81
+ }
82
+ </style>
@@ -5,7 +5,7 @@ import { Editor } from "@tiptap/vue-3";
5
5
  import { useI18n } from 'vue-i18n'
6
6
  import { computed, inject, onMounted, onUnmounted, Ref, ref, watch } from 'vue'
7
7
 
8
- import Dialog from "@tiptapify/components/UI/Dialog.vue"
8
+ import TiptapifyDialog from "@tiptapify/components/UI/TiptapifyDialog.vue"
9
9
 
10
10
  defineProps({
11
11
  variantBtn: { type: String, default() { return 'elevated' }},
@@ -63,7 +63,11 @@ function close() {
63
63
  }
64
64
 
65
65
  const showLink = (event: CustomEvent) => {
66
- attrs.value.href = event.detail.link?.href
66
+ if (event.detail.editorId !== editor.value.instanceId) {
67
+ return
68
+ }
69
+
70
+ attrs.value.href = event.detail.link?.href ?? ''
67
71
  attrs.value.target = targetAttrs.value.find(item => item.value === event.detail.link?.target) ?? targetAttrs[0]
68
72
  attrs.value.rel = event.detail.link?.rel?.split(' ')
69
73
  attrs.value.cssClass = event.detail.link?.class
@@ -80,14 +84,30 @@ onUnmounted(() => {
80
84
  })
81
85
 
82
86
  watch(() => attrs.value.href, () => {
83
- const regex = new RegExp(/^((https?|ftps?|sftp):\/\/[a-z0-9]+(\.[a-z0-9]+)+|mailto:\w+@[a-z]+(\.[a-z]+)*|tel:\+?\d+)$/, 'igu')
87
+ const azAZ09 = 'a-zA-Z0-9'
88
+
89
+ const regexHrefProto = 'https?:\\/\\/'
90
+ const regexHrefAuth = `([${azAZ09}]+(:[${azAZ09}]+)?@)?`
91
+ const regexHrefDomain = `[${azAZ09}]+(\\.[${azAZ09}]+(-?[${azAZ09}]+)?)+`
92
+ const regexHrefPath = `(\\/[${azAZ09}\\-]+)*`
93
+ const regexHrefFragment = '(#[^\\s]*)?'
94
+ const regexHrefQueryParam = `(\\?[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)?`
95
+ const regexHrefQueryParamExtra = `(&[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)*`
96
+ const regexHref = `${regexHrefProto}${regexHrefAuth}${regexHrefDomain}${regexHrefPath}${regexHrefFragment}${regexHrefQueryParam}${regexHrefQueryParamExtra}`
97
+
98
+ const regexMailto = `mailto:\\w+@[${azAZ09}]+(\\.[${azAZ09}]+)*`
99
+ const regexTel = 'tel:\\+?[0-9]+'
100
+
101
+ const regexAll = [regexHref, regexMailto, regexTel].join('|')
102
+
103
+ const regex = new RegExp(`^(${regexAll})$`, 'i')
84
104
 
85
- hrefInvalid.value = !regex.test(attrs.value.href)
105
+ hrefInvalid.value = attrs.value.href !== '' && !regex.test(attrs.value.href)
86
106
  })
87
107
  </script>
88
108
 
89
109
  <template>
90
- <Dialog ref="dialog" module="link">
110
+ <TiptapifyDialog ref="dialog" module="link">
91
111
  <template #content>
92
112
  <VCardText>
93
113
  <VRow>
@@ -146,12 +166,12 @@ watch(() => attrs.value.href, () => {
146
166
  <VBtn :variant="variantBtn" @click="close" class="mr-2">
147
167
  {{ t('dialog.close') }}
148
168
  </VBtn>
149
- <VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
169
+ <VBtn color="primary" :variant="variantBtn" :disabled="isDisabled || hrefInvalid" @click="apply">
150
170
  {{ t('dialog.apply') }}
151
171
  </VBtn>
152
172
  </VCol>
153
173
  </VRow>
154
174
  </VCardActions>
155
175
  </template>
156
- </Dialog>
176
+ </TiptapifyDialog>
157
177
  </template>