tiptapify 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { Editor } from "@tiptap/vue-3";
2
+ import type { DefineComponent } from 'vue'
3
+ import { extensionsComponents } from "./src/types/overridable-extensions";
4
+
5
+ export interface TiptapifyProps {
6
+ content: string|object
7
+ variantBtn: string
8
+ variantField: string
9
+ toolbar: boolean
10
+ items: [string]
11
+ itemsExclude: boolean
12
+ bubbleMenu: boolean
13
+ floatingMenu: boolean
14
+ slashCommands: boolean
15
+ placeholder: string
16
+ showWordsCount: boolean
17
+ showCharactersCount: boolean
18
+ defaultFontFamily: string
19
+ fontMeasure: string
20
+ rounded: string
21
+ overrideExtensionsComponents: extensionsComponents
22
+ }
23
+
24
+ export interface TiptapifyEmits {
25
+ 'editor-ready': (options: {
26
+ getHTML: () => string
27
+ getJSON: () => any
28
+ editor: Editor
29
+ }) => void
30
+ }
31
+
32
+ export declare const Tiptapify: DefineComponent<TiptapifyProps, {}, {}, {}, {}, {}, {}, TiptapifyEmits>
33
+
34
+ // Плагин
35
+ export interface TiptapifyOptions {
36
+ locale?: string
37
+ }
38
+
39
+ declare const TiptapifyPlugin: {
40
+ install: (app: any, options?: TiptapifyOptions) => void
41
+ }
42
+
43
+ export default TiptapifyPlugin
44
+
45
+ declare module '@vue/runtime-core' {
46
+ interface GlobalComponents {
47
+ Tiptapify: typeof Tiptapify
48
+ }
49
+ }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "tiptapify",
3
- "version": "0.0.8",
3
+ "types": "./index.d.ts",
4
+ "version": "0.0.9",
4
5
  "description": "Tiptap3 editor with Vuetify3 menu implementation",
5
6
  "exports": {
6
7
  ".": {
@@ -22,7 +23,8 @@
22
23
  "source": "./src/index.ts",
23
24
  "files": [
24
25
  "dist",
25
- "src"
26
+ "src",
27
+ "index.d.ts"
26
28
  ],
27
29
  "scripts": {
28
30
  "dev": "vite",
@@ -49,7 +51,7 @@
49
51
  "author": "Igor Voytovich",
50
52
  "license": "MIT",
51
53
  "repository": "https://github.com/IVoyt/tiptapify",
52
- "packageManager": "pnpm@10.11.1",
54
+ "packageManager": "pnpm@10.12.1",
53
55
  "dependencies": {
54
56
  "@tiptap/core": "next",
55
57
  "@tiptap/extension-blockquote": "next",
@@ -92,7 +94,7 @@
92
94
  "highlight.js": "^11.11.1",
93
95
  "linkifyjs": "^4.3.1",
94
96
  "lowlight": "^3.3.0",
95
- "vue-i18n": "^11.1.5"
97
+ "vue-i18n": "^11.1.6"
96
98
  },
97
99
  "peerDependencies": {
98
100
  "@mdi/js": "^7.4.47",
@@ -102,11 +104,11 @@
102
104
  "devDependencies": {
103
105
  "@intlify/unplugin-vue-i18n": "^6.0.8",
104
106
  "@rollup/plugin-alias": "^5.1.1",
105
- "@types/node": "^22.15.30",
107
+ "@types/node": "^22.15.32",
106
108
  "@vitejs/plugin-vue": "^5.2.4",
107
109
  "@vitejs/plugin-vue-jsx": "^4.2.0",
108
110
  "rollup-plugin-tsconfig-paths": "^1.5.2",
109
- "sass-embedded": "^1.89.1",
111
+ "sass-embedded": "^1.89.2",
110
112
  "typescript": "^5.8.3",
111
113
  "unplugin-vue-components": "^28.7.0",
112
114
  "vite": "^6.3.5",
@@ -1,17 +1,51 @@
1
1
  <script setup lang="ts">
2
2
  import { Editor } from "@tiptap/vue-3";
3
- import { inject, Ref } from "vue";
3
+ import { computed, inject, ref, Ref } from "vue";
4
+
5
+ import { useI18n } from "vue-i18n";
6
+
7
+ const props = defineProps({
8
+ showWordsCount: { type: Boolean, default: true },
9
+ showCharactersCount: { type: Boolean, default: true },
10
+ })
11
+
12
+ const { t } = useI18n()
4
13
 
5
14
  const editor = inject('tiptapifyEditor') as Ref<Editor>
15
+
16
+ const statusItems = ref([
17
+ {
18
+ enabled: computed(() => props.showWordsCount),
19
+ text: 'footer.words',
20
+ value: computed(() => editor.value.storage.characterCount.words())
21
+ },
22
+ {
23
+ enabled: computed(() => props.showCharactersCount),
24
+ text: 'footer.chars',
25
+ value: computed(() => editor.value.storage.characterCount.characters())
26
+ }
27
+ ])
28
+
29
+ function printStatusItemText(text: string): string {
30
+ return t(text)
31
+ }
32
+
33
+ function showFooter() {
34
+ return editor.value && (props.showWordsCount || props.showCharactersCount)
35
+ }
6
36
  </script>
7
37
 
8
38
  <template>
9
- <div v-if="editor" class="tiptapify-footer">
39
+ <div v-if="showFooter()" class="tiptapify-footer">
10
40
  <VRow>
11
41
  <VCol class="d-flex justify-end">
12
- <span class="words-count">
13
- {{ editor.storage.characterCount.words() }} words
14
- </span>
42
+ <template v-for="statusItem in statusItems" :key="statusItem.text">
43
+ <span v-if="statusItem.enabled" class="tiptapify-footer--status-item">
44
+ {{ printStatusItemText(statusItem.text) }}: {{ statusItem.value }}
45
+ </span>
46
+
47
+ <VDivider class="tiptapify-footer--divider" vertical />
48
+ </template>
15
49
  </VCol>
16
50
  </VRow>
17
51
  </div>
@@ -23,7 +57,15 @@ const editor = inject('tiptapifyEditor') as Ref<Editor>
23
57
  border-top: var(--border);
24
58
  }
25
59
 
26
- .words-count {
60
+ .tiptapify-footer--status-item {
27
61
  color: #999;
28
62
  }
63
+
64
+ .tiptapify-footer--divider:not(:last-child) {
65
+ margin: 0 8px;
66
+ }
67
+
68
+ .tiptapify-footer--divider:last-child {
69
+ display: none;
70
+ }
29
71
  </style>
@@ -1,16 +1,21 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import { onBeforeUnmount, provide, ref, ShallowRef, shallowRef, watch } from "vue";
3
+ import { extensionsComponents } from "@tiptapify/types/overridable-extensions";
4
+ import { computed, onBeforeUnmount, PropType, provide, ref, ShallowRef, watch } from "vue";
4
5
  import { default as Toolbar } from "@tiptapify/components/Toolbar/Index.vue";
5
6
  import { Editor, EditorContent } from '@tiptap/vue-3'
6
7
  import MenuBubble from '@tiptapify/components/MenuBubble.vue'
7
8
  import MenuFloating from '@tiptapify/components/MenuFloating.vue'
8
9
 
10
+ import { useI18n } from "vue-i18n";
11
+
9
12
  import { getTiptapEditor } from "@tiptapify/components/index";
10
13
 
11
14
  import Footer from '@tiptapify/components/Footer.vue'
12
15
  import { useTheme } from "vuetify/framework";
13
16
 
17
+ const { t } = useI18n();
18
+
14
19
  const props = defineProps({
15
20
  content: String|Object,
16
21
  variantBtn: { type: String, default () { return 'elevated' } },
@@ -21,17 +26,24 @@ const props = defineProps({
21
26
  bubbleMenu: { type: Boolean, default () { return true } },
22
27
  floatingMenu: { type: Boolean, default () { return true } },
23
28
  slashCommands: { type: Boolean, default () { return true } },
24
- placeholder: { type: String, default () { return 'Write something here...' } },
25
- showCharacterCount: { type: Boolean, default () { return true } },
29
+ placeholder: { type: String, default () { return '' } },
30
+ showWordsCount: { type: Boolean, default () { return true } },
31
+ showCharactersCount: { type: Boolean, default () { return true } },
26
32
  defaultFontFamily: { type: String, default () { return 'Inter' } },
27
33
  fontMeasure: { type: String, default () { return 'px' } },
28
34
  rounded: { type: String, default () { return '0' } },
35
+ overrideExtensionsComponents: { type: Object as PropType<extensionsComponents>, default() { return {} } },
29
36
  })
30
37
 
31
- const theme = ref(useTheme().current.value.dark ? 'dark' : 'light')
38
+ // console.log('override extension components', computed(() => props.overrideExtensionsComponents).value)
32
39
 
33
- const editor: ShallowRef<Editor | undefined> = shallowRef(
34
- getTiptapEditor(props.content, props.placeholder, props.slashCommands)
40
+ const appTheme = useTheme()
41
+ const currentTheme = ref(appTheme.global.name)
42
+
43
+ const editor: ShallowRef<Editor | undefined> = getTiptapEditor(
44
+ props.content,
45
+ computed(() => props.placeholder || t('content.placeholder')).value,
46
+ props.slashCommands
35
47
  )
36
48
 
37
49
  const emit = defineEmits(['update:modelValue', 'editor-ready']);
@@ -40,11 +52,10 @@ provide('tiptapifyEditor', editor)
40
52
 
41
53
  editor.value?.chain().setFontFamily(props.defaultFontFamily).run()
42
54
 
43
- defineExpose({ editor: editor });
44
-
45
55
  watch(() => editor.value, (editorInstance) => {
46
56
  if (editorInstance instanceof Editor) {
47
57
  emit('editor-ready', {
58
+ editor: editorInstance,
48
59
  getHTML: () => editorInstance.getHTML(),
49
60
  getJSON: () => editorInstance.getJSON(),
50
61
  });
@@ -69,21 +80,21 @@ onBeforeUnmount(() => {
69
80
  :items="items"
70
81
  :items-exclude="itemsExclude"
71
82
  :rounded="rounded"
83
+ :override-extensions-components="overrideExtensionsComponents"
84
+ :theme="currentTheme"
72
85
  />
73
86
  </template>
74
87
 
75
88
  <div :class="`border border-t-0 rounded-b-${rounded}`">
76
89
  <div class="pa-2 tiptapify-container">
77
- <MenuFloating v-if="floatingMenu" :variant="variantBtn" :theme="theme" />
90
+ <MenuFloating v-if="floatingMenu" :variant="variantBtn" :theme="currentTheme" />
78
91
 
79
- <MenuBubble v-if="bubbleMenu" :variant="variantBtn" :theme="theme" />
92
+ <MenuBubble v-if="bubbleMenu" :variant="variantBtn" :theme="currentTheme" />
80
93
 
81
94
  <EditorContent :editor="editor" class="tiptapify-editor" />
82
95
  </div>
83
96
 
84
- <template v-if="showCharacterCount">
85
- <Footer />
86
- </template>
97
+ <Footer :show-words-count="showWordsCount" :show-characters-count="showCharactersCount" />
87
98
  </div>
88
99
  </VCol>
89
100
  </VRow>
@@ -135,7 +146,6 @@ onBeforeUnmount(() => {
135
146
  background-repeat: no-repeat;
136
147
  background-position: right .1rem center;
137
148
  background-size: 1.25rem 1.25rem;
138
- /* padding-right: 1.25rem; */
139
149
 
140
150
  border-radius: .5rem;
141
151
  border: none;
@@ -150,8 +160,7 @@ onBeforeUnmount(() => {
150
160
  }
151
161
 
152
162
  /* List styles */
153
- ul,
154
- ol {
163
+ ul, ol {
155
164
  padding: 0 1rem;
156
165
  margin: 1.25rem 1rem 1.25rem 0.4rem;
157
166
 
@@ -192,19 +201,13 @@ onBeforeUnmount(() => {
192
201
  }
193
202
 
194
203
  /* Heading styles */
195
- h1,
196
- h2,
197
- h3,
198
- h4,
199
- h5,
200
- h6 {
204
+ h1, h2, h3, h4, h5, h6 {
201
205
  line-height: 1.1;
202
206
  margin-top: 2.5rem;
203
207
  text-wrap: pretty;
204
208
  }
205
209
 
206
- h1,
207
- h2 {
210
+ h1, h2 {
208
211
  margin-top: 3.5rem;
209
212
  margin-bottom: 1.5rem;
210
213
  }
@@ -221,9 +224,7 @@ onBeforeUnmount(() => {
221
224
  font-size: 1.1rem;
222
225
  }
223
226
 
224
- h4,
225
- h5,
226
- h6 {
227
+ h4, h5, h6 {
227
228
  font-size: 1rem;
228
229
  }
229
230
 
@@ -325,8 +326,7 @@ onBeforeUnmount(() => {
325
326
  table-layout: fixed;
326
327
  width: 100%;
327
328
 
328
- td,
329
- th {
329
+ td, th {
330
330
  border: 1px solid var(--gray-3);
331
331
  box-sizing: border-box;
332
332
  min-width: 1em;
@@ -368,6 +368,14 @@ onBeforeUnmount(() => {
368
368
  }
369
369
  }
370
370
 
371
+ p.is-editor-empty:first-child::before {
372
+ color: var(--gray-4);
373
+ content: attr(data-placeholder);
374
+ float: left;
375
+ height: 0;
376
+ pointer-events: none;
377
+ }
378
+
371
379
  .tableWrapper {
372
380
  margin: 1.5rem 0;
373
381
  overflow-x: auto;
@@ -1,22 +1,16 @@
1
1
  <script setup lang="ts">
2
+ import GroupBtn from "@tiptapify/components/Toolbar/GroupBtn.vue";
2
3
  import GroupDropdown from "@tiptapify/components/Toolbar/GroupDropdown.vue";
3
4
  import { defineProps, PropType } from 'vue'
4
- import { useI18n } from "vue-i18n";
5
5
 
6
6
  import { ToolbarItemSection } from "@tiptapify/components/Toolbar/items";
7
7
 
8
- import helpers from "@tiptapify/utils/helpers";
9
-
10
8
  defineProps({
11
9
  variant: { type: String, default () { return 'flat' }},
12
10
  section: { type: String, default() { return '' }},
13
11
  toolbarSection: { type: Object as PropType<ToolbarItemSection>, default() { return {} }}
14
12
  })
15
13
 
16
- const { t } = useI18n();
17
-
18
- const { ucFirst } = helpers;
19
-
20
14
  </script>
21
15
 
22
16
  <template>
@@ -26,14 +20,19 @@ const { ucFirst } = helpers;
26
20
  <GroupDropdown :toolbar-item="toolbarItem" :variant="variant" />
27
21
  </template>
28
22
 
29
- <VBtn v-else v-bind="toolbarItem.props" v-on="toolbarItem.attrs" size="32">
30
- <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
23
+ <VMenu v-else-if="toolbarItem?.component" v-model="toolbarItem.modelValue" :close-on-content-click="false">
24
+ <template #activator="{ props: menuProps }">
25
+ <GroupBtn v-bind="menuProps" :toolbar-item="toolbarItem" :variant="variant" />
26
+ </template>
27
+
28
+ <component
29
+ :is="toolbarItem.component"
30
+ v-bind="toolbarItem?.componentProps ?? {}"
31
+ @close="toolbarItem.modelValue = false"
32
+ />
33
+ </VMenu>
31
34
 
32
- <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
33
- <span v-else class="menu-item-title">
34
- {{ ucFirst(t(toolbarItem.name)) }}
35
- </span>
36
- </VBtn>
35
+ <GroupBtn v-else :toolbar-item="toolbarItem" :variant="variant" />
37
36
  </template>
38
37
  </VBtnGroup>
39
38
  </template>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import { defineProps, PropType } from 'vue'
3
+ import { useI18n } from "vue-i18n";
4
+
5
+ import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
6
+
7
+ import helpers from "@tiptapify/utils/helpers";
8
+
9
+ defineProps({
10
+ variant: { type: String, default () { return 'flat' }},
11
+ toolbarItem: { type: Object as PropType<ToolbarItem>, default() { return {} }}
12
+ })
13
+
14
+ const { t } = useI18n();
15
+
16
+ const { ucFirst } = helpers;
17
+ </script>
18
+
19
+ <template>
20
+ <VBtn v-bind="toolbarItem?.props ?? {}" v-on="toolbarItem?.attrs ?? {}" size="32">
21
+ <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
22
+
23
+ <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
24
+ <span v-else class="menu-item-title">
25
+ {{ ucFirst(t(toolbarItem.name)) }}
26
+ </span>
27
+
28
+ <VIcon v-if="toolbarItem.icon2" v-bind="toolbarItem?.icon2Props ?? {}" :icon="toolbarItem.icon2" size="small" style="position: absolute;" />
29
+ </VBtn>
30
+ </template>
31
+
32
+ <style lang="scss" scoped>
33
+
34
+ </style>
@@ -1,15 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  import { Editor } from "@tiptap/vue-3";
3
- import ImageDialog from "@tiptapify/extensions/components/ImageDialog.vue";
4
- import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
5
- import ShowSourceDialog from "@tiptapify/extensions/components/ShowSourceDialog.vue";
6
- import PreviewDialog from "@tiptapify/extensions/components/PreviewDialog.vue";
7
- import Group from "@tiptapify/components/Toolbar/Group.vue";
8
- import Toggle from "@tiptapify/components/Toolbar/Toggle.vue";
9
- import { computed, defineProps, inject, Ref, ref } from 'vue'
10
- import { useI18n } from "vue-i18n";
3
+ import { getDefaultComponents } from "@tiptapify/components/Toolbar/defaultExtensionComponents";
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'
11
7
 
12
- import { toolbarItems, ToolbarItemSections } from "@tiptapify/components/Toolbar/items";
8
+ import { toolbarItems } from "@tiptapify/components/Toolbar/items";
9
+ import { useTheme } from "vuetify/framework";
13
10
 
14
11
  const props = defineProps({
15
12
  variantBtn: { type: String, default () { return 'elevated' }},
@@ -22,95 +19,47 @@ const props = defineProps({
22
19
  customFontsOverride: { type: Boolean, default() { return false } },
23
20
  theme: { type: String, default() { return 'light' } },
24
21
  rounded: { type: String, default() { return '0' } },
22
+ toolbarScrollable: { type: Boolean, default() { return false } },
23
+ overrideExtensionsComponents: { type: Object as PropType<extensionsComponents>, default() { return {} } },
25
24
  })
26
25
 
27
- const { t } = useI18n();
28
-
29
26
  const editor = inject('tiptapifyEditor') as Ref<Editor>
30
27
 
28
+ const theme = useTheme()
29
+
31
30
  const items = toolbarItems(
32
31
  editor,
32
+ theme,
33
33
  computed(() => props.fontMeasure).value,
34
34
  { list: computed(() => props.items).value, exclude: computed(() => props.itemsExclude).value },
35
35
  computed(() => props.headingLevels).value
36
36
  )
37
- const toolbarItemsRef: Ref<ToolbarItemSections> = ref(items)
37
+
38
+ const defaultComponents: extensionsComponents = getDefaultComponents(props.variantField)
39
+
40
+ const extensions: ShallowRef<extensionsComponents> = shallowRef({})
41
+ Object.keys(defaultComponents).forEach(extension => {
42
+ extensions.value[extension] = props.overrideExtensionsComponents[extension] ?? defaultComponents[extension]
43
+ })
38
44
 
39
45
  </script>
40
46
 
41
47
  <template>
42
48
  <div v-if="editor">
43
- <VToolbar elevation="1" :theme="theme" height="auto" :class="`ps-1 rounded-t-${rounded}`">
44
- <VToolbarItems class="py-2">
45
- <template v-for="(toolbarSection, sectionKey) in toolbarItemsRef" :key="sectionKey">
46
- <Group v-if="toolbarSection.group" :variant="variantBtn" :toolbar-section="toolbarSection" />
47
-
48
- <Toggle v-else-if="toolbarSection.toggle" :variant="variantBtn" :toolbar-section="toolbarSection" />
49
-
50
- <VBtn
51
- v-else
52
- v-for="(toolbarItem, itemKey) in toolbarSection.items"
53
- :key="itemKey"
54
- :variant="variantBtn"
55
- v-bind="toolbarItem.props"
56
- v-on="toolbarItem.attrs"
57
- class="menu-button"
58
- size="32"
59
- elevation="4"
60
- rounded="sm"
61
- >
62
- <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
49
+ <VToolbar elevation="1" :theme="theme" height="auto" :class="`ps-1 pr-1 rounded-t-${rounded}`">
50
+ <VSlideGroup v-if="toolbarScrollable">
51
+ <Items :items="items" />
52
+ </VSlideGroup>
63
53
 
64
- <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="16" />
65
- <span v-else class="menu-item-title">
66
- {{ t(toolbarItem.name) }}
67
- </span>
68
- </VBtn>
69
-
70
- <div class="menu-divider"></div>
71
- </template>
72
- </VToolbarItems>
54
+ <Items v-else :items="items" />
73
55
  </VToolbar>
74
56
 
75
- <ImageDialog :variant-field="variantField" />
76
- <LinkDialog :variant-field="variantField" />
77
- <PreviewDialog />
78
- <ShowSourceDialog :variant-field="variantField" />
57
+ <template v-for="extension in extensions">
58
+ <component :is="extension.component" v-bind="extension?.props ?? {}" />
59
+ </template>
79
60
  </div>
80
61
  </template>
81
62
 
82
63
  <style lang="scss" scoped>
83
- .tiptapify-menu {
84
- padding: 8px;
85
- border-bottom: var(--border);
86
- }
87
-
88
- :deep(.toolbar__items) {
89
- flex-wrap: wrap;
90
- }
91
-
92
- :deep(.v-btn-group) {
93
- height: 32px !important;
94
- }
95
-
96
- .menu-item-title {
97
- font-size: 14px;
98
- }
99
-
100
- .menu-button {
101
- margin: 0 1px;
102
- }
103
-
104
- .menu-divider {
105
- margin: 0 4px;
106
- }
107
-
108
- .menu-divider:nth-last-child(1) {
109
- display: none;
110
- }
111
64
 
112
- .v-toolbar-items {
113
- flex-wrap: wrap;
114
- row-gap: 5px;
115
- }
116
65
  </style>
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ import Group from "@tiptapify/components/Toolbar/Group.vue";
3
+ import Toggle from "@tiptapify/components/Toolbar/Toggle.vue";
4
+ import { computed, defineProps, PropType, Ref, ref } from 'vue'
5
+ import { useI18n } from "vue-i18n";
6
+
7
+ import { ToolbarItemSections } from "@tiptapify/components/Toolbar/items";
8
+
9
+ const props = defineProps({
10
+ variantBtn: { type: String, default () { return 'elevated' }},
11
+ items: { type: Object as PropType<ToolbarItemSections>, default() { return {} }},
12
+ })
13
+
14
+ const { t } = useI18n();
15
+
16
+ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(computed(() => props.items).value)
17
+
18
+ </script>
19
+
20
+ <template>
21
+ <VToolbarItems class="py-2">
22
+ <template v-for="(toolbarSection, sectionKey) in toolbarItemsRef" :key="sectionKey">
23
+ <Group v-if="toolbarSection.group" :variant="variantBtn" :toolbar-section="toolbarSection" />
24
+
25
+ <Toggle v-else-if="toolbarSection.toggle" :variant="variantBtn" :toolbar-section="toolbarSection" />
26
+
27
+ <VBtn
28
+ v-else
29
+ v-for="(toolbarItem, itemKey) in toolbarSection.items"
30
+ :key="itemKey"
31
+ :variant="variantBtn"
32
+ v-bind="toolbarItem.props"
33
+ v-on="toolbarItem.attrs"
34
+ class="menu-button"
35
+ size="32"
36
+ elevation="4"
37
+ rounded="sm"
38
+ >
39
+ <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
40
+
41
+ <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="16" />
42
+ <span v-else class="menu-item-title">
43
+ {{ t(toolbarItem.name) }}
44
+ </span>
45
+ </VBtn>
46
+
47
+ <div class="menu-divider"></div>
48
+ </template>
49
+ </VToolbarItems>
50
+ </template>
51
+
52
+ <style lang="scss" scoped>
53
+ :deep(.v-btn-group) {
54
+ height: 32px !important;
55
+ }
56
+
57
+ .menu-item-title {
58
+ font-size: 14px;
59
+ }
60
+
61
+ .menu-button {
62
+ margin: 0 1px;
63
+ }
64
+
65
+ .menu-divider {
66
+ margin: 0 4px;
67
+ }
68
+
69
+ .menu-divider:nth-last-child(1) {
70
+ display: none;
71
+ }
72
+
73
+ .v-toolbar-items {
74
+ flex-wrap: wrap;
75
+ row-gap: 5px;
76
+ }
77
+ </style>
@@ -0,0 +1,32 @@
1
+ import ImageDialog from "@tiptapify/extensions/components/ImageDialog.vue";
2
+ import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
3
+ import PreviewDialog from "@tiptapify/extensions/components/PreviewDialog.vue";
4
+ import ShowSourceDialog from "@tiptapify/extensions/components/ShowSourceDialog.vue";
5
+ import { extensionsComponents } from "@tiptapify/types/overridable-extensions";
6
+ import { computed } from "vue";
7
+
8
+ export function getDefaultComponents(variantField: string): extensionsComponents {
9
+ return {
10
+ image: {
11
+ component: ImageDialog,
12
+ props: {
13
+ variantField: computed(() => variantField).value,
14
+ }
15
+ },
16
+ link: {
17
+ component: LinkDialog,
18
+ props: {
19
+ variantField: computed(() => variantField).value,
20
+ }
21
+ },
22
+ preview: {
23
+ component: PreviewDialog,
24
+ },
25
+ showSource: {
26
+ component: ShowSourceDialog,
27
+ props: {
28
+ variantField: computed(() => variantField).value,
29
+ }
30
+ }
31
+ }
32
+ }