tiptapify 0.0.11 → 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 (94) hide show
  1. package/README.md +6 -2
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/tiptapify.mjs +16191 -15808
  4. package/dist/tiptapify.umd.js +73 -33
  5. package/index.d.ts +2 -2
  6. package/package.json +2 -1
  7. package/src/components/MenuBubble.vue +8 -8
  8. package/src/components/Tiptapify.vue +4 -5
  9. package/src/components/Toolbar/Group.vue +2 -2
  10. package/src/components/Toolbar/GroupBtn.vue +11 -8
  11. package/src/components/Toolbar/GroupDropdown.vue +3 -17
  12. package/src/components/Toolbar/Index.vue +13 -10
  13. package/src/components/Toolbar/Items.vue +3 -6
  14. package/src/components/Toolbar/Toggle.vue +2 -4
  15. package/src/components/Toolbar/defaultExtensionComponents.ts +34 -13
  16. package/src/components/Toolbar/items.ts +43 -60
  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 +16 -1
  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 +5 -31
  57. package/src/composables/Toolbar/useAlignmentItems.ts +9 -59
  58. package/src/composables/Toolbar/useFormatExtraItems.ts +11 -72
  59. package/src/composables/Toolbar/useFormatItems.ts +9 -59
  60. package/src/composables/Toolbar/useListItems.ts +11 -69
  61. package/src/composables/Toolbar/useMediaItems.ts +7 -209
  62. package/src/composables/Toolbar/useMiscItems.ts +13 -58
  63. package/src/composables/Toolbar/useStyleItems.ts +14 -228
  64. package/src/extensions/components/ImageDialog.vue +7 -3
  65. package/src/extensions/components/LinkDialog.vue +7 -3
  66. package/src/extensions/components/PreviewDialog.vue +11 -4
  67. package/src/extensions/components/ShowSourceDialog.vue +7 -4
  68. package/src/extensions/components/StyleColor.vue +2 -2
  69. package/src/extensions/components/slashCommands/CommandsList.vue +1 -4
  70. package/src/extensions/image.ts +2 -1
  71. package/src/extensions/link.ts +2 -1
  72. package/src/extensions/preview.ts +2 -1
  73. package/src/extensions/view-source.ts +2 -1
  74. package/src/i18n/index.ts +1 -0
  75. package/src/i18n/locales/ch.json +2 -1
  76. package/src/i18n/locales/cz.json +2 -1
  77. package/src/i18n/locales/de.json +2 -1
  78. package/src/i18n/locales/en.json +2 -1
  79. package/src/i18n/locales/es.json +2 -1
  80. package/src/i18n/locales/fr.json +2 -1
  81. package/src/i18n/locales/it.json +2 -1
  82. package/src/i18n/locales/la.json +2 -1
  83. package/src/i18n/locales/lt.json +2 -1
  84. package/src/i18n/locales/nl.json +2 -1
  85. package/src/i18n/locales/pl.json +2 -1
  86. package/src/i18n/locales/pt.json +2 -1
  87. package/src/i18n/locales/ru.json +2 -1
  88. package/src/i18n/locales/se.json +2 -1
  89. package/src/i18n/locales/ua.json +2 -1
  90. package/src/index.ts +3 -1
  91. package/src/types/extensionComponents.ts +22 -0
  92. package/src/types/toolbarItems.ts +43 -0
  93. package/src/types/toolbarSections.ts +11 -0
  94. package/src/types/overridable-extensions.ts +0 -6
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Editor } from "@tiptap/vue-3";
2
2
  import type { DefineComponent } from 'vue'
3
- import { extensionsComponents } from "./src/types/overridable-extensions";
3
+ import { extensionComponents } from "./src/types/extensionComponents";
4
4
 
5
5
  export interface TiptapifyProps {
6
6
  content: string|object
@@ -18,7 +18,7 @@ export interface TiptapifyProps {
18
18
  defaultFontFamily: string
19
19
  fontMeasure: string
20
20
  rounded: string
21
- overrideExtensionsComponents: extensionsComponents
21
+ customExtensions: extensionComponents
22
22
  }
23
23
 
24
24
  export interface TiptapifyEmits {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tiptapify",
3
3
  "types": "./index.d.ts",
4
- "version": "0.0.11",
4
+ "version": "0.0.12",
5
5
  "description": "Tiptap3 editor with Vuetify3 menu implementation",
6
6
  "exports": {
7
7
  ".": {
@@ -69,6 +69,7 @@
69
69
  "@tiptap/extension-highlight": "^3.0.7",
70
70
  "@tiptap/extension-horizontal-rule": "^3.0.7",
71
71
  "@tiptap/extension-image": "^3.0.7",
72
+ "@tiptap/extension-invisible-characters": "^3.0.7",
72
73
  "@tiptap/extension-italic": "^3.0.7",
73
74
  "@tiptap/extension-link": "^3.0.7",
74
75
  "@tiptap/extension-list": "^3.0.7",
@@ -14,7 +14,7 @@ const editor = inject('tiptapifyEditor') as Ref<Editor>
14
14
  const items = ref([
15
15
  {
16
16
  name: 'bold',
17
- icon: mdi.mdiFormatBold,
17
+ icon: `mdiSvg:${mdi.mdiFormatBold}`,
18
18
  props: {
19
19
  disabled: computed(() => !editor?.value.can().chain().focus().toggleBold().run()),
20
20
  color: computed(() => editor.value.isActive('bold') ? 'primary' : ''),
@@ -23,7 +23,7 @@ const items = ref([
23
23
  },
24
24
  {
25
25
  name: 'italic',
26
- icon: mdi.mdiFormatItalic,
26
+ icon: `mdiSvg:${mdi.mdiFormatItalic}`,
27
27
  props: {
28
28
  disabled: computed(() => !editor.value.can().chain().focus().toggleItalic().run()),
29
29
  color: computed(() => editor.value.isActive('italic') ? 'primary' : ''),
@@ -32,7 +32,7 @@ const items = ref([
32
32
  },
33
33
  {
34
34
  name: 'strike',
35
- icon: mdi.mdiFormatStrikethroughVariant,
35
+ icon: `mdiSvg:${mdi.mdiFormatStrikethroughVariant}`,
36
36
  props: {
37
37
  disabled: computed(() => !editor.value.can().chain().focus().toggleStrike().run()),
38
38
  color: computed(() => editor.value.isActive('strike') ? 'primary' : ''),
@@ -41,7 +41,7 @@ const items = ref([
41
41
  },
42
42
  {
43
43
  name: 'underline',
44
- icon: mdi.mdiFormatUnderline,
44
+ icon: `mdiSvg:${mdi.mdiFormatUnderline}`,
45
45
  props: {
46
46
  disabled: computed(() => !editor.value.can().chain().focus().toggleUnderline().run()),
47
47
  color: computed(() => editor.value.isActive('underline') ? 'primary' : ''),
@@ -50,7 +50,7 @@ const items = ref([
50
50
  },
51
51
  {
52
52
  name: 'highlight',
53
- icon: mdi.mdiFormatColorHighlight,
53
+ icon: `mdiSvg:${mdi.mdiFormatColorHighlight}`,
54
54
  props: {
55
55
  disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
56
56
  color: computed(() => editor.value.isActive('highlight') ? 'primary' : ''),
@@ -59,7 +59,7 @@ const items = ref([
59
59
  },
60
60
  {
61
61
  name: 'code',
62
- icon: mdi.mdiXml,
62
+ icon: `mdiSvg:${mdi.mdiXml}`,
63
63
  props: {
64
64
  disabled: computed(() => !editor.value.can().chain().focus().toggleCode().run()),
65
65
  color: computed(() => editor.value.isActive('code') ? 'primary' : ''),
@@ -68,7 +68,7 @@ const items = ref([
68
68
  },
69
69
  {
70
70
  name: 'link',
71
- icon: computed(() => editor.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
71
+ icon: computed(() => editor.value.isActive('link') ? `mdiSvg:${mdi.mdiLinkOff}` : `mdiSvg:${mdi.mdiLink}`),
72
72
  props: {
73
73
  color: computed(() => editor.value.isActive('link') ? 'primary' : ''),
74
74
  disabled: computed(() => editor.value.isActive('code') || editor.value.isActive('codeBlock')),
@@ -77,7 +77,7 @@ const items = ref([
77
77
  },
78
78
  {
79
79
  name: 'format clear',
80
- icon: mdi.mdiFormatClear,
80
+ icon: `mdiSvg:${mdi.mdiFormatClear}`,
81
81
  click: () => editor.value.chain().focus().unsetAllMarks().clearNodes().run(),
82
82
  }
83
83
  ])
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import { extensionsComponents } from "@tiptapify/types/overridable-extensions";
3
+ import { extensionComponents } from "@tiptapify/types/extensionComponents";
4
4
  import { computed, onBeforeUnmount, PropType, provide, ref, ShallowRef, watch } from "vue";
5
5
  import { default as Toolbar } from "@tiptapify/components/Toolbar/Index.vue";
6
6
  import { Editor, EditorContent } from '@tiptap/vue-3'
@@ -32,18 +32,17 @@ const props = defineProps({
32
32
  defaultFontFamily: { type: String, default () { return 'Inter' } },
33
33
  fontMeasure: { type: String, default () { return 'px' } },
34
34
  rounded: { type: String, default () { return '0' } },
35
- customExtensions: { type: Object as PropType<extensionsComponents>, default() { return {} } },
35
+ customExtensions: { type: Object as PropType<extensionComponents>, default() { return {} } },
36
36
  })
37
37
 
38
- // console.log('override extension components', computed(() => props.overrideExtensionsComponents).value)
39
-
40
38
  const appTheme = useTheme()
41
39
  const currentTheme = ref(appTheme.global.name)
42
40
 
43
41
  const editor: ShallowRef<Editor | undefined> = getTiptapEditor(
44
42
  props.content,
45
43
  computed(() => props.placeholder || t('content.placeholder')).value,
46
- props.slashCommands
44
+ props.slashCommands,
45
+ props.customExtensions
47
46
  )
48
47
 
49
48
  const emit = defineEmits(['update:modelValue', 'editor-ready']);
@@ -3,7 +3,7 @@ import GroupBtn from "@tiptapify/components/Toolbar/GroupBtn.vue";
3
3
  import GroupDropdown from "@tiptapify/components/Toolbar/GroupDropdown.vue";
4
4
  import { defineProps, PropType } from 'vue'
5
5
 
6
- import { ToolbarItemSection } from "@tiptapify/components/Toolbar/items";
6
+ import { ToolbarItemSection } from "@tiptapify/types/toolbarItems";
7
7
 
8
8
  defineProps({
9
9
  variant: { type: String, default () { return 'flat' }},
@@ -20,7 +20,7 @@ defineProps({
20
20
  <GroupDropdown :toolbar-item="toolbarItem" :variant="variant" />
21
21
  </template>
22
22
 
23
- <VMenu v-else-if="toolbarItem?.component" v-model="toolbarItem.modelValue" :close-on-content-click="false">
23
+ <VMenu v-else-if="toolbarItem?.component" v-model="toolbarItem.modelValue" :close-on-content-click="false" v-bind="toolbarItem.props">
24
24
  <template #activator="{ props: menuProps }">
25
25
  <GroupBtn v-bind="menuProps" :toolbar-item="toolbarItem" :variant="variant" />
26
26
  </template>
@@ -1,27 +1,30 @@
1
1
  <script setup lang="ts">
2
+ import BtnIcon from "@tiptapify/components/UI/BtnIcon.vue";
2
3
  import { defineProps, PropType } from 'vue'
3
- import { useI18n } from "vue-i18n";
4
4
 
5
- import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
5
+
6
+ import { ToolbarItem } from '@tiptapify/types/toolbarItems'
6
7
 
7
8
  defineProps({
8
9
  variant: { type: String, default () { return 'flat' }},
9
10
  toolbarItem: { type: Object as PropType<ToolbarItem>, default() { return {} }}
10
11
  })
11
12
 
12
- const { t } = useI18n();
13
13
  </script>
14
14
 
15
15
  <template>
16
16
  <VBtn v-bind="toolbarItem?.props ?? {}" v-on="toolbarItem?.attrs ?? {}" size="32">
17
17
  <VTooltip :text="toolbarItem.tooltip" location="top" activator="parent" />
18
18
 
19
- <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
20
- <span v-else class="menu-item-title">
21
- {{ toolbarItem.name }}
22
- </span>
19
+ <BtnIcon :icon="toolbarItem.icon" />
23
20
 
24
- <VIcon v-if="toolbarItem.icon2" v-bind="toolbarItem?.icon2Props ?? {}" :icon="toolbarItem.icon2" size="small" style="position: absolute;" />
21
+ <VIcon
22
+ v-if="toolbarItem.icon2"
23
+ v-bind="toolbarItem?.icon2Props ?? {}"
24
+ :icon="toolbarItem.icon2"
25
+ size="small"
26
+ style="position: absolute;"
27
+ />
25
28
  </VBtn>
26
29
  </template>
27
30
 
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { defineProps, PropType } from 'vue'
3
- import { useI18n } from "vue-i18n";
3
+ import * as mdi from '@mdi/js'
4
4
 
5
5
  import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
6
6
 
@@ -10,8 +10,6 @@ defineProps({
10
10
  toolbarItem: { type: Object as PropType<ToolbarItem>, default() { return {} }}
11
11
  })
12
12
 
13
- const { t } = useI18n();
14
-
15
13
  </script>
16
14
 
17
15
  <template>
@@ -20,10 +18,7 @@ const { t } = useI18n();
20
18
  <VBtn v-bind="{ ...menuProps, ...toolbarItem.props }" size="32">
21
19
  <VTooltip :text="toolbarItem.tooltip" location="top" activator="parent" />
22
20
 
23
- <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
24
- <span v-else class="menu-item-title">
25
- {{ toolbarItem.name }}
26
- </span>
21
+ <VIcon :icon="toolbarItem.icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="small" />
27
22
  </VBtn>
28
23
  </template>
29
24
 
@@ -45,16 +40,7 @@ const { t } = useI18n();
45
40
  >
46
41
  <VTooltip v-if="item.tooltip" :text="item.tooltip" location="top" activator="parent" />
47
42
 
48
- <VIcon v-if="item.icon" :icon="item.icon" size="small" />
49
-
50
- <span v-else class="menu-item-title">
51
- <template v-if="item.noI18n">
52
- {{ item.name }}
53
- </template>
54
- <template v-else>
55
- {{ item.toggle }}
56
- </template>
57
- </span>
43
+ <VIcon :icon="item.icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="small" />
58
44
 
59
45
  <VMenu
60
46
  v-if="item.component"
@@ -2,8 +2,8 @@
2
2
  import { Editor } from "@tiptap/vue-3";
3
3
  import { getDefaultComponents } from "@tiptapify/components/Toolbar/defaultExtensionComponents";
4
4
  import Items from "@tiptapify/components/Toolbar/Items.vue";
5
- import { computed, defineProps, inject, PropType, ref, Ref, ShallowRef, shallowRef, triggerRef } from 'vue'
6
- import { extensionsComponents } from '@tiptapify/types/overridable-extensions'
5
+ import { computed, defineProps, inject, PropType, Ref, ShallowRef, shallowRef } from 'vue'
6
+ import { extensionComponents, ToolbarItemType } from '@tiptapify/types/extensionComponents'
7
7
 
8
8
  import { toolbarItems } from "@tiptapify/components/Toolbar/items";
9
9
  import { useTheme } from "vuetify/framework";
@@ -20,7 +20,7 @@ const props = defineProps({
20
20
  theme: { type: String, default() { return 'light' } },
21
21
  rounded: { type: String, default() { return '0' } },
22
22
  toolbarScrollable: { type: Boolean, default() { return false } },
23
- customExtensions: { type: Object as PropType<extensionsComponents>, default() { return {} } },
23
+ customExtensions: { type: Object as PropType<extensionComponents>, default() { return {} } },
24
24
  })
25
25
 
26
26
  const editor = inject('tiptapifyEditor') as Ref<Editor>
@@ -28,18 +28,21 @@ const editor = inject('tiptapifyEditor') as Ref<Editor>
28
28
  const appTheme = useTheme()
29
29
 
30
30
  const items = toolbarItems(
31
- editor,
32
31
  appTheme,
33
32
  computed(() => props.fontMeasure).value,
34
33
  { list: computed(() => props.items).value, exclude: computed(() => props.itemsExclude).value },
35
- computed(() => props.headingLevels).value
34
+ computed(() => props.headingLevels).value,
35
+ props.customExtensions
36
36
  )
37
37
 
38
- const defaultComponents: extensionsComponents = getDefaultComponents(props.variantField)
38
+ const defaultComponents: extensionComponents = getDefaultComponents(props.variantField)
39
39
 
40
- const extensions: ShallowRef<extensionsComponents> = shallowRef({})
40
+ const extensions: ShallowRef<extensionComponents> = shallowRef({})
41
41
  Object.keys(defaultComponents).forEach(extension => {
42
- extensions.value[extension] = props.customExtensions[extension] ?? defaultComponents[extension]
42
+ extensions.value[extension] = defaultComponents[extension]
43
+ })
44
+ Object.keys(props.customExtensions).forEach(extension => {
45
+ extensions.value[extension] = props.customExtensions[extension]
43
46
  })
44
47
 
45
48
  </script>
@@ -54,9 +57,9 @@ Object.keys(defaultComponents).forEach(extension => {
54
57
  <Items v-else :items="items" />
55
58
  </VToolbar>
56
59
 
57
- <!-- mount components mentioned in "items" -->
60
+ <!-- mount built-in and/or custom components -->
58
61
  <template v-for="extension in extensions">
59
- <component :is="extension.component" v-bind="extension?.props ?? {}" />
62
+ <component v-if="extension.type !== ToolbarItemType.dropdown" :is="extension.component" v-bind="{ ...extension?.props ?? {}, ...extension?.componentProps ?? {} }" />
60
63
  </template>
61
64
  </div>
62
65
  </template>
@@ -2,17 +2,14 @@
2
2
  import Group from "@tiptapify/components/Toolbar/Group.vue";
3
3
  import Toggle from "@tiptapify/components/Toolbar/Toggle.vue";
4
4
  import { computed, defineProps, PropType, Ref, ref } from 'vue'
5
- import { useI18n } from "vue-i18n";
6
5
 
7
- import { ToolbarItemSections } from "@tiptapify/components/Toolbar/items";
6
+ import { ToolbarItemSections } from "@tiptapify/types/toolbarItems";
8
7
 
9
8
  const props = defineProps({
10
9
  variantBtn: { type: String, default () { return 'elevated' }},
11
10
  items: { type: Object as PropType<ToolbarItemSections>, default() { return {} }},
12
11
  })
13
12
 
14
- const { t } = useI18n();
15
-
16
13
  const toolbarItemsRef: Ref<ToolbarItemSections> = ref(computed(() => props.items).value)
17
14
 
18
15
  </script>
@@ -29,8 +26,8 @@ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(computed(() => props.items
29
26
  v-for="(toolbarItem, itemKey) in toolbarSection.items"
30
27
  :key="itemKey"
31
28
  :variant="variantBtn"
32
- v-bind="toolbarItem.props"
33
- v-on="toolbarItem.attrs"
29
+ v-bind="toolbarItem?.props ?? {}"
30
+ v-on="toolbarItem?.attrs ?? {}"
34
31
  class="menu-button"
35
32
  size="32"
36
33
  elevation="4"
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { defineProps, PropType } from 'vue'
3
3
  import { useI18n } from "vue-i18n";
4
+ import * as mdi from '@mdi/js'
4
5
 
5
6
  import { ToolbarItemSection } from "@tiptapify/components/Toolbar/items";
6
7
 
@@ -19,10 +20,7 @@ const { t } = useI18n();
19
20
  <VBtn v-bind="item.props" v-on="item.attrs" size="32">
20
21
  <VTooltip :text="item.name" location="top" activator="parent" />
21
22
 
22
- <VIcon v-if="item.icon" :icon="item.icon" size="small" />
23
- <span v-else class="menu-item-title">
24
- {{ item.name }}
25
- </span>
23
+ <VIcon :icon="item.icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="small" />
26
24
  </VBtn>
27
25
  </template>
28
26
  </VBtnToggle>
@@ -1,32 +1,53 @@
1
+ import { useImage } from "@tiptapify/composables/Toolbar/Media/useImage";
2
+ import { useLink } from "@tiptapify/composables/Toolbar/Media/useLink";
3
+ import { usePreview } from "@tiptapify/composables/Toolbar/Misc/usePreview";
4
+ import { useSource } from "@tiptapify/composables/Toolbar/Misc/useSource";
1
5
  import ImageDialog from "@tiptapify/extensions/components/ImageDialog.vue";
2
6
  import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
3
7
  import PreviewDialog from "@tiptapify/extensions/components/PreviewDialog.vue";
4
8
  import ShowSourceDialog from "@tiptapify/extensions/components/ShowSourceDialog.vue";
5
- import { extensionsComponents } from "@tiptapify/types/overridable-extensions";
6
- import { computed } from "vue";
9
+ import { extensionComponents } from "@tiptapify/types/extensionComponents";
10
+ import { ToolbarSections } from "@tiptapify/types/toolbarSections";
11
+ import { computed, markRaw } from "vue";
7
12
 
8
- export function getDefaultComponents(variantField: string): extensionsComponents {
13
+ export function getDefaultComponents(variantField: string): extensionComponents {
9
14
  return {
10
15
  image: {
11
- component: ImageDialog,
12
- props: {
16
+ component: markRaw(ImageDialog),
17
+ componentProps: {
13
18
  variantField: computed(() => variantField).value,
14
- }
19
+ },
20
+ section: ToolbarSections.media,
21
+ name: useImage().name,
22
+ tooltip: useImage().tooltip,
23
+ icon: useImage().icon,
15
24
  },
16
25
  link: {
17
- component: LinkDialog,
18
- props: {
26
+ component: markRaw(LinkDialog),
27
+ componentProps: {
19
28
  variantField: computed(() => variantField).value,
20
- }
29
+ },
30
+ section: ToolbarSections.media,
31
+ name: useLink().name,
32
+ tooltip: useLink().tooltip,
33
+ icon: useLink().icon,
21
34
  },
22
35
  preview: {
23
- component: PreviewDialog,
36
+ component: markRaw(PreviewDialog),
37
+ section: ToolbarSections.misc,
38
+ name: usePreview().name,
39
+ tooltip: usePreview().tooltip,
40
+ icon: usePreview().icon,
24
41
  },
25
42
  showSource: {
26
- component: ShowSourceDialog,
27
- props: {
43
+ component: markRaw(ShowSourceDialog),
44
+ componentProps: {
28
45
  variantField: computed(() => variantField).value,
29
- }
46
+ },
47
+ section: ToolbarSections.misc,
48
+ name: useSource().name,
49
+ tooltip: useSource().tooltip,
50
+ icon: useSource().icon,
30
51
  }
31
52
  }
32
53
  }
@@ -6,63 +6,26 @@ import { useListItems } from "@tiptapify/composables/Toolbar/useListItems";
6
6
  import { useMediaItems } from "@tiptapify/composables/Toolbar/useMediaItems";
7
7
  import { useMiscItems } from "@tiptapify/composables/Toolbar/useMiscItems";
8
8
  import { useStyleItems } from "@tiptapify/composables/Toolbar/useStyleItems";
9
- import { ComputedRef, ref } from "vue";
10
-
11
- interface ToolbarItemAttrs {
12
- [key: string]: Function | any
13
- }
14
-
15
- interface ToolbarItemProps {
16
- [key: string]: any
17
- }
18
-
19
- export interface ToolbarItem {
20
- name: string|number|ComputedRef<string>,
21
- tooltip: string|ComputedRef<string>,
22
- icon: string|ComputedRef<string>,
23
- icon2?: string|ComputedRef<string>,
24
- noI18n?: boolean,
25
- enabled: boolean,
26
- component?: any,
27
- modelValue?: any,
28
- group?: boolean,
29
- toggle?: boolean,
30
- icon2Props?: ToolbarItemProps,
31
- componentProps?: ToolbarItemProps,
32
- props?: ToolbarItemProps,
33
- attrs?: ToolbarItemAttrs,
34
- children?: ToolbarItems|ToolbarItem[],
35
- }
36
-
37
- export interface ToolbarItems {
38
- [key: string]: ToolbarItem
39
- }
40
-
41
- export interface ToolbarItemSection {
42
- group?: boolean,
43
- toggle?: boolean,
44
- items: ToolbarItems,
45
- }
46
-
47
- export interface ToolbarItemSections {
48
- [key: string]: ToolbarItemSection
49
- }
9
+ import { extensionComponents } from "@tiptapify/types/extensionComponents";
10
+ import { ref } from "vue";
11
+
12
+ import { ToolbarItem, ToolbarItemSections } from '@tiptapify/types/toolbarItems'
50
13
 
51
14
  export function toolbarItems(
52
- editor: any,
53
15
  theme: any,
54
16
  fontMeasure: string,
55
- items: { list: Array<string>, exclude: boolean },
56
- customHeadingLevels: Array<number>
17
+ items: { list: Array<ToolbarItem>, exclude: boolean },
18
+ customHeadingLevels: Array<number>,
19
+ customExtensions: extensionComponents
57
20
  ): ToolbarItemSections {
58
- const styleItems = ref(useStyleItems(editor.value, theme, fontMeasure, customHeadingLevels))
59
- const formatItems = ref(useFormatItems(editor.value))
60
- const formatExtraItems = ref(useFormatExtraItems(editor.value))
61
- const alignmentItems = ref(useAlignmentItems(editor.value))
62
- const listItems = ref(useListItems(editor.value))
63
- const actionsItems = ref(useActionsItems(editor.value))
64
- const miscItems = ref(useMiscItems(editor.value))
65
- const mediaItems = ref(useMediaItems(editor.value))
21
+ const styleItems = ref(useStyleItems(theme, fontMeasure, customHeadingLevels))
22
+ const formatItems = ref(useFormatItems())
23
+ const formatExtraItems = ref(useFormatExtraItems())
24
+ const alignmentItems = ref(useAlignmentItems())
25
+ const listItems = ref(useListItems())
26
+ const actionsItems = ref(useActionsItems())
27
+ const miscItems = ref(useMiscItems())
28
+ const mediaItems = ref(useMediaItems())
66
29
 
67
30
  const allMenuItems: ToolbarItemSections = {
68
31
  /**
@@ -78,6 +41,7 @@ export function toolbarItems(
78
41
  list: { group: true, items: listItems.value },
79
42
  actions: { group: true, items: actionsItems.value },
80
43
  misc: { group: true, items: miscItems.value },
44
+ extra: { group: true, items: {} },
81
45
  }
82
46
 
83
47
  const pluginsList: Array<string> = []
@@ -85,13 +49,13 @@ export function toolbarItems(
85
49
  Object.keys(allMenuItems[section]).forEach(item => pluginsList.push(item))
86
50
  })
87
51
 
88
- if (items.list.length) {
89
- items.list.forEach(item => {
90
- if (!pluginsList.includes(item)) {
91
- throw new Error(`Unknown plugin name: ${item}! Supported plugins: ${pluginsList.join(', ')}`)
92
- }
93
- })
94
- }
52
+ // if (items.list.length) {
53
+ // items.list.forEach(item => {
54
+ // if (!pluginsList.includes(item)) {
55
+ // throw new Error(`Unknown plugin name: ${item}! Supported plugins: ${pluginsList.join(', ')}`)
56
+ // }
57
+ // })
58
+ // }
95
59
 
96
60
  const toolbarItems: ToolbarItemSections = {}
97
61
 
@@ -100,7 +64,7 @@ export function toolbarItems(
100
64
  Object.keys(allMenuItems).forEach(sectionName => {
101
65
  const section = allMenuItems[sectionName]
102
66
  Object.keys(section.items).forEach(plugin => {
103
- const item = section.items[plugin]
67
+ const item: ToolbarItem = section.items[plugin]
104
68
 
105
69
  if (items.list.length) {
106
70
  item.enabled = items.list.includes(plugin)
@@ -132,5 +96,24 @@ export function toolbarItems(
132
96
  }
133
97
  })
134
98
 
99
+ // add/override custom extensions
100
+ Object.keys(customExtensions).forEach(extension => {
101
+ const section = customExtensions[extension].section
102
+
103
+ if (typeof customExtensions[extension]?.props === 'undefined') {
104
+ customExtensions[extension].props = toolbarItems[section]?.items[extension]?.props ?? {}
105
+ }
106
+
107
+ if (typeof customExtensions[extension]?.attrs === 'undefined') {
108
+ customExtensions[extension].attrs = toolbarItems[section]?.items[extension]?.attrs ?? {}
109
+ }
110
+
111
+ if (typeof toolbarItems[section] === 'undefined') {
112
+ toolbarItems[section] = { group: true, items: {} }
113
+ toolbarItems[section].items[extension] = {}
114
+ }
115
+ toolbarItems[section].items[extension] = customExtensions[extension]
116
+ })
117
+
135
118
  return toolbarItems
136
119
  }
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { defineProps } from 'vue'
3
+ import * as mdi from '@mdi/js'
4
+
5
+ defineProps({
6
+ icon: String
7
+ })
8
+
9
+ const isSvgString = (icon: any) => {
10
+ return typeof icon === 'string' && icon.includes('<svg')
11
+ }
12
+ </script>
13
+
14
+ <template>
15
+ <div v-if="isSvgString(icon)" v-html="icon" class="v-icon tiptapify-btn-svg-icon"></div>
16
+ <VIcon v-else :icon="icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="small" />
17
+ </template>
18
+
19
+ <style lang="scss" scoped>
20
+ .tiptapify-btn-svg-icon {
21
+ width: 16px;
22
+ height: 16px;
23
+ }
24
+ </style>
@@ -6,6 +6,7 @@ import { useI18n } from "vue-i18n";
6
6
 
7
7
  const props = defineProps({
8
8
  module: String,
9
+ title: String,
9
10
  fullscreen: { type: Boolean, default () { return false } },
10
11
  maxWidth: { type: Number, default () { return 800 } },
11
12
  })
@@ -103,17 +104,17 @@ watch(() => dialog.value, async () => {
103
104
  </script>
104
105
 
105
106
  <template>
106
- <VDialog v-model="dialog" :max-width="maxWidth" :fullscreen="fullscreen" absolute @click:outside="emitClose">
107
+ <VDialog v-model="dialog" :max-width="maxWidth" :fullscreen="fullscreen" @click:outside="emitClose">
107
108
  <VCard>
108
109
  <VCardTitle ref="movableHandler" :class="`d-flex ${!fullscreen ? 'tiptapify-movable-handler' : ''}`" style="user-select: none;">
109
110
  <VLabel>
110
- {{ t(`dialog.${module}.title`) }}
111
+ {{ title ?? t(`dialog.${module}.title`) }}
111
112
  </VLabel>
112
113
 
113
114
  <VSpacer />
114
115
 
115
116
  <VBtn density="compact" class="tiptapify-dialog-close" variant="elevated" elevation="4" icon @click="emitClose">
116
- <VIcon size="x-small" :icon="mdi.mdiClose" />
117
+ <VIcon size="x-small" :icon="`mdiSvg:${mdi.mdiClose}`" />
117
118
  </VBtn>
118
119
  </VCardTitle>
119
120
 
@@ -22,6 +22,7 @@ import { TextAlign } from '@tiptap/extension-text-align'
22
22
  import { Underline } from '@tiptap/extension-underline'
23
23
  import { TableKit } from '@tiptap/extension-table'
24
24
  import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'
25
+ import { InvisibleCharacters } from '@tiptap/extension-invisible-characters'
25
26
 
26
27
  import { TiptapifyLink } from '@tiptapify/extensions/link'
27
28
  import { TiptapifyImage } from '@tiptapify/extensions/image'
@@ -30,6 +31,7 @@ import { ViewSource } from '@tiptapify/extensions/view-source'
30
31
  import { Preview } from '@tiptapify/extensions/preview'
31
32
  import SlashCommands from '@tiptapify/extensions/slash-commands'
32
33
  import suggestion from '@tiptapify/extensions/components/slashCommands/suggestion'
34
+ import { extensionComponents } from "@tiptapify/types/extensionComponents";
33
35
 
34
36
  // load all languages with "all" or common languages with "common"
35
37
  import { common, createLowlight } from 'lowlight'
@@ -47,7 +49,7 @@ const lowlight = createLowlight(common)
47
49
  // register language example
48
50
  // lowlight.register('ts', ts)
49
51
 
50
- export function editorExtensions (placeholder: string, slashCommands: boolean) {
52
+ export function editorExtensions (placeholder: string, slashCommands: boolean, customExtensions: extensionComponents) {
51
53
  const extensions = [
52
54
  TextStyleKit,
53
55
  Document,
@@ -94,6 +96,9 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
94
96
  Placeholder.configure({ placeholder }),
95
97
  CharacterCount,
96
98
  ViewSource,
99
+ InvisibleCharacters.configure({
100
+ visible: false,
101
+ }),
97
102
  Preview
98
103
  ]
99
104
 
@@ -101,5 +106,15 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
101
106
  extensions.push(SlashCommands.configure({ suggestion }))
102
107
  }
103
108
 
109
+ if (Object.keys(customExtensions).length) {
110
+ for (const customExtension of Object.values(customExtensions)) {
111
+ if (typeof customExtension.extensions !== 'undefined') {
112
+ for (const extension of customExtension.extensions) {
113
+ extensions.push(extension)
114
+ }
115
+ }
116
+ }
117
+ }
118
+
104
119
  return extensions
105
120
  }