tiptapify 0.0.6 → 0.0.7

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 (37) hide show
  1. package/README.md +3 -2
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/{tiptapify.es.js → tiptapify.mjs} +52865 -52006
  4. package/dist/tiptapify.umd.js +41 -43
  5. package/package.json +8 -8
  6. package/src/components/Footer.vue +5 -6
  7. package/src/components/MenuBubble.vue +39 -30
  8. package/src/components/MenuFloating.vue +10 -10
  9. package/src/components/Tiptapify.vue +89 -10
  10. package/src/components/Toolbar/Group.vue +8 -43
  11. package/src/components/Toolbar/GroupDropdown.vue +85 -0
  12. package/src/components/Toolbar/Index.vue +11 -10
  13. package/src/components/Toolbar/items/media.ts +179 -2
  14. package/src/components/Toolbar/items/misc.ts +10 -1
  15. package/src/components/Toolbar/items/style.ts +2 -2
  16. package/src/components/Toolbar/items.ts +1 -0
  17. package/src/components/editorExtensions.ts +6 -4
  18. package/src/components/index.ts +13 -0
  19. package/src/{components/extensions → extensions}/components/LinkDialog.vue +11 -8
  20. package/src/extensions/components/PreviewDialog.vue +45 -0
  21. package/src/{components/extensions/components/ShowSource.vue → extensions/components/ShowSourceDialog.vue} +11 -7
  22. package/src/extensions/components/TableBuilder.vue +138 -0
  23. package/src/extensions/preview.ts +53 -0
  24. package/src/{components/extensions → extensions}/view-source.ts +1 -3
  25. package/src/i18n/locales/de.json +64 -45
  26. package/src/i18n/locales/en.json +21 -2
  27. package/src/i18n/locales/es.json +27 -8
  28. package/src/i18n/locales/fr.json +26 -7
  29. package/src/i18n/locales/it.json +36 -17
  30. package/src/i18n/locales/pl.json +28 -9
  31. package/src/i18n/locales/ru.json +21 -2
  32. package/src/i18n/locales/ua.json +21 -2
  33. package/src/utils/helpers.ts +17 -0
  34. package/src/composable/useEditor.ts +0 -35
  35. /package/src/{components/extensions → extensions}/components/slashCommands/CommandsList.vue +0 -0
  36. /package/src/{components/extensions → extensions}/components/slashCommands/suggestion.ts +0 -0
  37. /package/src/{components/extensions → extensions}/slash-commands.ts +0 -0
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "tiptapify",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Tiptap3 editor with Vuetify3 menu implementation",
5
5
  "exports": {
6
6
  ".": {
7
7
  "import": {
8
- "default": "./dist/tiptapify.es.js",
8
+ "default": "./dist/tiptapify.mjs",
9
9
  "development": "./src/index.ts"
10
10
  },
11
11
  "require": {
@@ -18,7 +18,7 @@
18
18
  "./style.css": "./dist/tiptapify.css"
19
19
  },
20
20
  "main": "./dist/tiptapify.umd.cjs",
21
- "module": "./dist/tiptapify.js",
21
+ "module": "./dist/tiptapify.mjs",
22
22
  "source": "./src/index.ts",
23
23
  "files": [
24
24
  "dist",
@@ -49,7 +49,7 @@
49
49
  "author": "Igor Voytovich",
50
50
  "license": "MIT",
51
51
  "repository": "https://github.com/IVoyt/tiptapify",
52
- "packageManager": "pnpm@10.11.0",
52
+ "packageManager": "pnpm@10.11.1",
53
53
  "dependencies": {
54
54
  "@tiptap/core": "next",
55
55
  "@tiptap/extension-blockquote": "next",
@@ -92,7 +92,7 @@
92
92
  "highlight.js": "^11.11.1",
93
93
  "linkifyjs": "^4.3.1",
94
94
  "lowlight": "^3.3.0",
95
- "vue-i18n": "^11.1.4"
95
+ "vue-i18n": "^11.1.5"
96
96
  },
97
97
  "peerDependencies": {
98
98
  "@mdi/js": "^7.4.47",
@@ -102,13 +102,13 @@
102
102
  "devDependencies": {
103
103
  "@intlify/unplugin-vue-i18n": "^6.0.8",
104
104
  "@rollup/plugin-alias": "^5.1.1",
105
- "@types/node": "^22.15.21",
105
+ "@types/node": "^22.15.30",
106
106
  "@vitejs/plugin-vue": "^5.2.4",
107
107
  "@vitejs/plugin-vue-jsx": "^4.2.0",
108
108
  "rollup-plugin-tsconfig-paths": "^1.5.2",
109
- "sass-embedded": "^1.89.0",
109
+ "sass-embedded": "^1.89.1",
110
110
  "typescript": "^5.8.3",
111
- "unplugin-vue-components": "^28.5.0",
111
+ "unplugin-vue-components": "^28.7.0",
112
112
  "vite": "^6.3.5",
113
113
  "vite-plugin-vuetify": "^2.1.1",
114
114
  "vite-svg-loader": "^5.1.0",
@@ -1,17 +1,16 @@
1
1
  <script setup lang="ts">
2
- import { useEditor } from "@tiptapify/composable/useEditor";
3
- import { ref } from 'vue'
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import { inject, Ref } from "vue";
4
4
 
5
- const { editor } = useEditor()
6
- const editorInstance = ref(editor.getInstance())
5
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
7
6
  </script>
8
7
 
9
8
  <template>
10
- <div v-if="editorInstance" class="tiptapify-footer">
9
+ <div v-if="editor" class="tiptapify-footer">
11
10
  <VRow>
12
11
  <VCol class="d-flex justify-end">
13
12
  <span class="words-count">
14
- {{ editorInstance.storage.characterCount.words() }} words
13
+ {{ editor.storage.characterCount.words() }} words
15
14
  </span>
16
15
  </VCol>
17
16
  </VRow>
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
- import LinkDialog from "@tiptapify/components/extensions/components/LinkDialog.vue";
3
- import { useEditor } from "@tiptapify/composable/useEditor";
4
- import { computed, defineProps, ref } from "vue";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
4
+ import { computed, defineProps, inject, Ref, ref } from "vue";
5
5
  import { BubbleMenu } from '@tiptap/vue-3/menus'
6
6
  import * as mdi from '@mdi/js'
7
7
 
@@ -10,8 +10,7 @@ defineProps({
10
10
  theme: { type: String, default () { return 'light' }},
11
11
  })
12
12
 
13
- const { editor } = useEditor()
14
- const editorInstance = ref(editor.getInstance())
13
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
15
14
 
16
15
  const bubbleMenuLinkButton = ref(null)
17
16
 
@@ -20,81 +19,91 @@ const items = ref([
20
19
  name: 'bold',
21
20
  icon: mdi.mdiFormatBold,
22
21
  props: {
23
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleBold().run()),
24
- color: computed(() => editorInstance.value.isActive('bold') ? 'primary' : ''),
22
+ disabled: computed(() => !editor?.value.can().chain().focus().toggleBold().run()),
23
+ color: computed(() => editor.value.isActive('bold') ? 'primary' : ''),
25
24
  },
26
- click: () => editorInstance.value.chain().focus().toggleBold().run(),
25
+ click: () => editor.value.chain().focus().toggleBold().run(),
27
26
  },
28
27
  {
29
28
  name: 'italic',
30
29
  icon: mdi.mdiFormatItalic,
31
30
  props: {
32
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleItalic().run()),
33
- color: computed(() => editorInstance.value.isActive('italic') ? 'primary' : ''),
31
+ disabled: computed(() => !editor.value.can().chain().focus().toggleItalic().run()),
32
+ color: computed(() => editor.value.isActive('italic') ? 'primary' : ''),
34
33
  },
35
- click: () => editorInstance.value.chain().focus().toggleItalic().run(),
34
+ click: () => editor.value.chain().focus().toggleItalic().run(),
36
35
  },
37
36
  {
38
37
  name: 'strike',
39
38
  icon: mdi.mdiFormatStrikethroughVariant,
40
39
  props: {
41
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleStrike().run()),
42
- color: computed(() => editorInstance.value.isActive('strike') ? 'primary' : ''),
40
+ disabled: computed(() => !editor.value.can().chain().focus().toggleStrike().run()),
41
+ color: computed(() => editor.value.isActive('strike') ? 'primary' : ''),
43
42
  },
44
- click: () => editorInstance.value.chain().focus().toggleStrike().run(),
43
+ click: () => editor.value.chain().focus().toggleStrike().run(),
45
44
  },
46
45
  {
47
46
  name: 'underline',
48
47
  icon: mdi.mdiFormatUnderline,
49
48
  props: {
50
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleUnderline().run()),
51
- color: computed(() => editorInstance.value.isActive('underline') ? 'primary' : ''),
49
+ disabled: computed(() => !editor.value.can().chain().focus().toggleUnderline().run()),
50
+ color: computed(() => editor.value.isActive('underline') ? 'primary' : ''),
52
51
  },
53
- click: () => editorInstance.value.chain().focus().toggleUnderline().run(),
52
+ click: () => editor.value.chain().focus().toggleUnderline().run(),
54
53
  },
55
54
  {
56
55
  name: 'highlight',
57
56
  icon: mdi.mdiFormatColorHighlight,
58
57
  props: {
59
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleHighlight().run()),
60
- color: computed(() => editorInstance.value.isActive('highlight') ? 'primary' : ''),
58
+ disabled: computed(() => !editor.value.can().chain().focus().toggleHighlight().run()),
59
+ color: computed(() => editor.value.isActive('highlight') ? 'primary' : ''),
61
60
  },
62
- click: () => editorInstance.value.chain().focus().toggleHighlight().run(),
61
+ click: () => editor.value.chain().focus().toggleHighlight().run(),
63
62
  },
64
63
  {
65
64
  name: 'code',
66
65
  icon: mdi.mdiXml,
67
66
  props: {
68
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleCode().run()),
69
- color: computed(() => editorInstance.value.isActive('code') ? 'primary' : ''),
67
+ disabled: computed(() => !editor.value.can().chain().focus().toggleCode().run()),
68
+ color: computed(() => editor.value.isActive('code') ? 'primary' : ''),
70
69
  },
71
- click: () => editorInstance.value.chain().focus().toggleCode().run(),
70
+ click: () => editor.value.chain().focus().toggleCode().run(),
72
71
  },
73
72
  {
74
73
  name: 'link',
75
- icon: computed(() => editorInstance.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
74
+ icon: computed(() => editor.value.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
76
75
  props: {
77
- color: computed(() => editorInstance.value.isActive('link') ? 'primary' : ''),
78
- disabled: computed(() => editorInstance.value.isActive('code') || editorInstance.value.isActive('codeBlock')),
76
+ color: computed(() => editor.value.isActive('link') ? 'primary' : ''),
77
+ disabled: computed(() => editor.value.isActive('code') || editor.value.isActive('codeBlock')),
79
78
  },
80
79
  click: () => linkAction(),
81
80
  },
82
81
  {
83
82
  name: 'format clear',
84
83
  icon: mdi.mdiFormatClear,
85
- click: () => editorInstance.value.chain().focus().unsetAllMarks().clearNodes().run(),
84
+ click: () => editor.value.chain().focus().unsetAllMarks().clearNodes().run(),
86
85
  }
87
86
  ])
88
87
 
89
88
  function linkAction() {
90
- return editorInstance.value.isActive('link')
91
- ? editorInstance.value.chain().focus().unsetLink().run()
89
+ return editor.value.isActive('link')
90
+ ? editor.value.chain().focus().unsetLink().run()
92
91
  : bubbleMenuLinkButton.value?.open()
93
92
  }
94
93
  </script>
95
94
 
96
95
  <template>
97
- <BubbleMenu v-if="editorInstance" :editor="editorInstance" :options="{ placement: 'bottom' }">
96
+ <BubbleMenu
97
+ v-if="editor"
98
+ :editor="editor"
99
+ :options="{ placement: 'bottom' }"
100
+ :shouldShow="({ editor, view, state, from, to }) => {
101
+ const docSize = editor.state.doc.content.size
102
+ const isAllSelected = from === 0 && to === docSize
103
+
104
+ return (from !== to) && !isAllSelected
105
+ }"
106
+ >
98
107
  <div class="bubble-menu">
99
108
  <VCard>
100
109
  <VCardText class="pa-0">
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { useEditor } from "@tiptapify/composable/useEditor";
3
- import { defineProps, ref } from "vue";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import { defineProps, inject, Ref } from "vue";
4
4
  import { FloatingMenu } from '@tiptap/vue-3/menus'
5
5
  import * as mdi from '@mdi/js'
6
6
 
@@ -9,11 +9,11 @@ defineProps({
9
9
  theme: { type: String, default () { return 'light' }},
10
10
  })
11
11
 
12
- const editorInstance = ref(useEditor().editor.getInstance())
12
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
13
13
  </script>
14
14
 
15
15
  <template>
16
- <FloatingMenu v-if="editorInstance" :editor="editorInstance">
16
+ <FloatingMenu v-if="editor" :editor="editor">
17
17
  <div class="floating-menu">
18
18
  <VCard>
19
19
  <VCardText class="pa-0">
@@ -21,22 +21,22 @@ const editorInstance = ref(useEditor().editor.getInstance())
21
21
  <VToolbarItems>
22
22
  <VBtnGroup divided density="compact">
23
23
  <VBtn
24
- @click="editorInstance.chain().focus().toggleHeading({ level: 1 }).run()"
25
- :color="`${editorInstance.isActive('heading', { level: 1 }) ? 'primary' : ''}`"
24
+ @click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
25
+ :color="`${editor.isActive('heading', { level: 1 }) ? 'primary' : ''}`"
26
26
  size="small"
27
27
  >
28
28
  <VIcon :icon="mdi['mdiFormatHeader1']" size="16" />
29
29
  </VBtn>
30
30
  <VBtn
31
- @click="editorInstance.chain().focus().toggleHeading({ level: 2 }).run()"
32
- :color="`${editorInstance.isActive('heading', { level: 2 }) ? 'primary' : ''}`"
31
+ @click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
32
+ :color="`${editor.isActive('heading', { level: 2 }) ? 'primary' : ''}`"
33
33
  size="small"
34
34
  >
35
35
  <VIcon :icon="mdi['mdiFormatHeader2']" size="16" />
36
36
  </VBtn>
37
37
  <VBtn
38
- @click="editorInstance.chain().focus().toggleBulletList().run()"
39
- :color="`${editorInstance.isActive('bulletList') ? 'primary' : ''}`"
38
+ @click="editor.chain().focus().toggleBulletList().run()"
39
+ :color="`${editor.isActive('bulletList') ? 'primary' : ''}`"
40
40
  size="small"
41
41
  >
42
42
  <VIcon :icon="mdi['mdiFormatListBulleted']" size="16" />
@@ -1,12 +1,13 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import { onBeforeUnmount, ref } from "vue";
3
+ import { onBeforeUnmount, provide, ref, ShallowRef, shallowRef, watch } from "vue";
4
4
  import { default as Toolbar } from "@tiptapify/components/Toolbar/Index.vue";
5
- import { EditorContent } from '@tiptap/vue-3'
6
- import { useEditor } from '@tiptapify/composable/useEditor'
5
+ import { Editor, EditorContent } from '@tiptap/vue-3'
7
6
  import MenuBubble from '@tiptapify/components/MenuBubble.vue'
8
7
  import MenuFloating from '@tiptapify/components/MenuFloating.vue'
9
8
 
9
+ import { getTiptapEditor } from "@tiptapify/components/index";
10
+
10
11
  import Footer from '@tiptapify/components/Footer.vue'
11
12
  import { useTheme } from "vuetify/framework";
12
13
 
@@ -28,14 +29,30 @@ const props = defineProps({
28
29
 
29
30
  const theme = ref(useTheme().current.value.dark ? 'dark' : 'light')
30
31
 
31
- const editor = useEditor(props.content, props.placeholder, props.slashCommands).editor
32
- const editorInstance = ref(editor.getInstance())
33
- editorInstance?.value?.chain().setFontFamily(props.defaultFontFamily).run()
32
+ const editor: ShallowRef<Editor | undefined> = shallowRef(
33
+ getTiptapEditor(props.content, props.placeholder, props.slashCommands)
34
+ )
35
+
36
+ const emit = defineEmits(['update:modelValue', 'editor-ready']);
37
+
38
+ provide('tiptapifyEditor', editor)
39
+
40
+ editor.value?.chain().setFontFamily(props.defaultFontFamily).run()
41
+
42
+ defineExpose({ editor: editor });
43
+
44
+ watch(() => editor.value, (editorInstance) => {
45
+ if (editorInstance instanceof Editor) {
46
+ emit('editor-ready', {
47
+ getHTML: () => editorInstance.getHTML(),
48
+ getJSON: () => editorInstance.getJSON(),
49
+ });
50
+ }
51
+ }, { immediate: true });
34
52
 
35
53
  onBeforeUnmount(() => {
36
- editor.destroy()
54
+ editor.value?.destroy()
37
55
  })
38
-
39
56
  </script>
40
57
 
41
58
  <template>
@@ -44,7 +61,7 @@ onBeforeUnmount(() => {
44
61
  <VCol>
45
62
  <template v-if="toolbar">
46
63
  <Toolbar
47
- v-if="editorInstance"
64
+ v-if="editor"
48
65
  :variant="variant"
49
66
  :font-measure="fontMeasure"
50
67
  :items="items"
@@ -59,7 +76,7 @@ onBeforeUnmount(() => {
59
76
 
60
77
  <MenuBubble v-if="bubbleMenu" :variant="variant" :theme="theme" />
61
78
 
62
- <EditorContent :editor="editorInstance" class="tiptapify-editor" />
79
+ <EditorContent :editor="editor" class="tiptapify-editor" />
63
80
  </div>
64
81
 
65
82
  <template v-if="showCharacterCount">
@@ -297,5 +314,67 @@ onBeforeUnmount(() => {
297
314
  border-top: 1px solid var(--gray-2);
298
315
  margin: 2rem 0;
299
316
  }
317
+
318
+ /* Table-specific styling */
319
+ table {
320
+ border-collapse: collapse;
321
+ margin: 0;
322
+ overflow: hidden;
323
+ table-layout: fixed;
324
+ width: 100%;
325
+
326
+ td,
327
+ th {
328
+ border: 1px solid var(--gray-3);
329
+ box-sizing: border-box;
330
+ min-width: 1em;
331
+ padding: 6px 8px;
332
+ position: relative;
333
+ vertical-align: top;
334
+
335
+ > * {
336
+ margin-bottom: 0;
337
+ }
338
+ }
339
+
340
+ th {
341
+ background-color: var(--gray-1);
342
+ font-weight: bold;
343
+ text-align: left;
344
+ }
345
+
346
+ .selectedCell:after {
347
+ background: var(--gray-2);
348
+ content: '';
349
+ left: 0;
350
+ right: 0;
351
+ top: 0;
352
+ bottom: 0;
353
+ pointer-events: none;
354
+ position: absolute;
355
+ z-index: 2;
356
+ }
357
+
358
+ .column-resize-handle {
359
+ background-color: var(--purple);
360
+ bottom: -2px;
361
+ pointer-events: none;
362
+ position: absolute;
363
+ right: -2px;
364
+ top: 0;
365
+ width: 4px;
366
+ }
367
+ }
368
+
369
+ .tableWrapper {
370
+ margin: 1.5rem 0;
371
+ overflow-x: auto;
372
+ }
373
+
374
+ &.resize-cursor {
375
+ cursor: ew-resize;
376
+ cursor: col-resize;
377
+ }
378
+
300
379
  }
301
380
  </style>
@@ -1,9 +1,12 @@
1
1
  <script setup lang="ts">
2
+ import GroupDropdown from "@tiptapify/components/Toolbar/GroupDropdown.vue";
2
3
  import { defineProps, PropType } from 'vue'
3
4
  import { useI18n } from "vue-i18n";
4
5
 
5
6
  import { ToolbarItemSection } from "@tiptapify/components/Toolbar/items";
6
7
 
8
+ import helpers from "@tiptapify/utils/helpers";
9
+
7
10
  defineProps({
8
11
  variant: { type: String, default () { return 'flat' }},
9
12
  section: { type: String, default() { return '' }},
@@ -12,61 +15,23 @@ defineProps({
12
15
 
13
16
  const { t } = useI18n();
14
17
 
18
+ const { ucFirst } = helpers;
19
+
15
20
  </script>
16
21
 
17
22
  <template>
18
23
  <VBtnGroup :variant="variant" elevation="4">
19
24
  <template v-for="(toolbarItem, toolbarItemKey) in toolbarSection.items" :key="toolbarItemKey">
20
25
  <template v-if="toolbarItem.children">
21
- <VMenu>
22
- <template #activator="{ props: menuProps }">
23
- <VBtn v-bind="{ ...menuProps, ...toolbarItem.props }" size="32">
24
- <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
25
-
26
- <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
27
- <span v-else class="menu-item-title">
28
- {{ t(toolbarItem.name) }}
29
- </span>
30
- </VBtn>
31
- </template>
32
-
33
- <VList v-model="toolbarItem.modelValue" max-height="430px">
34
- <VListItem
35
- v-for="(item, menuItemKey) in toolbarItem.children"
36
- :key="menuItemKey"
37
- :value="item.name"
38
- density="compact"
39
- class="pa-0"
40
- >
41
- <VBtn
42
- variant="flat"
43
- rounded="0"
44
- v-bind="item.props"
45
- v-on="item.attrs"
46
- >
47
- <VTooltip v-if="item.tooltip" :text="t(item.tooltip)" location="top" activator="parent" />
48
-
49
- <VIcon v-if="item.icon" :icon="item.icon" size="small" />
50
- <span v-else class="menu-item-title">
51
- <template v-if="item.noI18n">
52
- {{ item.name }}
53
- </template>
54
- <template v-else>
55
- {{ t(item.toggle) }}
56
- </template>
57
- </span>
58
- </VBtn>
59
- </VListItem>
60
- </VList>
61
- </VMenu>
26
+ <GroupDropdown :toolbar-item="toolbarItem" :variant="variant" />
62
27
  </template>
63
28
 
64
29
  <VBtn v-else v-bind="toolbarItem.props" v-on="toolbarItem.attrs" size="32">
65
- <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
30
+ <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
66
31
 
67
32
  <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
68
33
  <span v-else class="menu-item-title">
69
- {{ t(toolbarItem.name) }}
34
+ {{ ucFirst(t(toolbarItem.name)) }}
70
35
  </span>
71
36
  </VBtn>
72
37
  </template>
@@ -0,0 +1,85 @@
1
+ <script setup lang="ts">
2
+ import { defineProps, PropType } from 'vue'
3
+ import { useI18n } from "vue-i18n";
4
+
5
+ import helpers from "@tiptapify/utils/helpers";
6
+
7
+ import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
8
+
9
+ const { ucFirst } = helpers;
10
+
11
+ defineProps({
12
+ variant: { type: String, default () { return 'flat' }},
13
+ nested: { type: Boolean, default () { return false }},
14
+ toolbarItem: { type: Object as PropType<ToolbarItem>, default() { return {} }}
15
+ })
16
+
17
+ const { t } = useI18n();
18
+
19
+ </script>
20
+
21
+ <template>
22
+ <VMenu v-model="toolbarItem.modelValue" v-bind="toolbarItem.props">
23
+ <template v-if="!nested" #activator="{ props: menuProps }">
24
+ <VBtn v-bind="{ ...menuProps, ...toolbarItem.props }" size="32">
25
+ <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
26
+
27
+ <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
28
+ <span v-else class="menu-item-title">
29
+ {{ ucFirst(t(toolbarItem.name)) }}
30
+ </span>
31
+ </VBtn>
32
+ </template>
33
+
34
+ <VList v-model="toolbarItem.modelValue" max-height="430px">
35
+ <VListItem
36
+ v-for="(item, menuItemKey) in toolbarItem.children"
37
+ :key="menuItemKey"
38
+ :value="item.name"
39
+ density="compact"
40
+ class="pa-0"
41
+ >
42
+ <VBtn
43
+ variant="text"
44
+ block
45
+ class="justify-start"
46
+ rounded="0"
47
+ v-bind="item.props ?? {}"
48
+ v-on="item?.attrs ?? {}"
49
+ >
50
+ <VTooltip v-if="item.tooltip" :text="ucFirst(t(item.tooltip))" location="top" activator="parent" />
51
+
52
+ <VIcon v-if="item.icon" :icon="item.icon" size="small" />
53
+
54
+ <span v-else class="menu-item-title">
55
+ <template v-if="item.noI18n">
56
+ {{ item.name }}
57
+ </template>
58
+ <template v-else>
59
+ {{ ucFirst(t(item.toggle)) }}
60
+ </template>
61
+ </span>
62
+
63
+ <VMenu
64
+ v-if="item.component"
65
+ v-bind="item.props"
66
+ >
67
+ <VList>
68
+ <VListItem density="compact">
69
+ <component :is="item.component" @close="toolbarItem.modelValue = false" />
70
+ </VListItem>
71
+ </VList>
72
+ </VMenu>
73
+
74
+ <template v-if="item.children?.length">
75
+ <GroupDropdown :toolbar-item="item" variant="outline" :nested="true" />
76
+ </template>
77
+ </VBtn>
78
+ </VListItem>
79
+ </VList>
80
+ </VMenu>
81
+ </template>
82
+
83
+ <style lang="scss" scoped>
84
+
85
+ </style>
@@ -1,10 +1,11 @@
1
1
  <script setup lang="ts">
2
- import LinkDialog from "@tiptapify/components/extensions/components/LinkDialog.vue";
3
- import ShowSource from "@tiptapify/components/extensions/components/ShowSource.vue";
2
+ import { Editor } from "@tiptap/vue-3";
3
+ import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
4
+ import ShowSourceDialog from "@tiptapify/extensions/components/ShowSourceDialog.vue";
5
+ import PreviewDialog from "@tiptapify/extensions/components/PreviewDialog.vue";
4
6
  import Group from "@tiptapify/components/Toolbar/Group.vue";
5
7
  import Toggle from "@tiptapify/components/Toolbar/Toggle.vue";
6
- import { useEditor } from "@tiptapify/composable/useEditor";
7
- import { computed, defineProps, Ref, ref } from 'vue'
8
+ import { computed, defineProps, inject, Ref, ref } from 'vue'
8
9
  import { useI18n } from "vue-i18n";
9
10
 
10
11
  import { toolbarItems, ToolbarItemSections } from "@tiptapify/components/Toolbar/items";
@@ -23,13 +24,12 @@ const props = defineProps({
23
24
 
24
25
  const { t } = useI18n();
25
26
 
26
- const { editor } = useEditor()
27
- const editorInstance = ref(editor.getInstance())
27
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
28
28
 
29
29
  const toolbarLinkButton = ref(null)
30
30
 
31
31
  const items = toolbarItems(
32
- editorInstance,
32
+ editor,
33
33
  computed(() => props.fontMeasure).value,
34
34
  { list: computed(() => props.items).value, exclude: computed(() => props.itemsExclude).value },
35
35
  computed(() => props.headingLevels).value,
@@ -64,8 +64,8 @@ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(items)
64
64
 
65
65
  <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="16" />
66
66
  <span v-else class="menu-item-title">
67
- {{ t(toolbarItem.name) }}
68
- </span>
67
+ {{ t(toolbarItem.name) }}
68
+ </span>
69
69
  </VBtn>
70
70
 
71
71
  <div class="menu-divider"></div>
@@ -74,7 +74,8 @@ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(items)
74
74
  </VToolbar>
75
75
 
76
76
  <LinkDialog ref="toolbarLinkButton" />
77
- <ShowSource />
77
+ <PreviewDialog />
78
+ <ShowSourceDialog />
78
79
  </div>
79
80
  </template>
80
81