tiptapify 0.0.7 → 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.
Files changed (40) hide show
  1. package/README.md +27 -3
  2. package/dist/tiptapify.css +1 -1
  3. package/dist/tiptapify.mjs +27785 -23593
  4. package/dist/tiptapify.umd.js +35 -35
  5. package/index.d.ts +49 -0
  6. package/package.json +8 -6
  7. package/src/components/Footer.vue +48 -6
  8. package/src/components/MenuBubble.vue +5 -12
  9. package/src/components/Tiptapify.vue +41 -31
  10. package/src/components/Toolbar/Group.vue +13 -14
  11. package/src/components/Toolbar/GroupBtn.vue +34 -0
  12. package/src/components/Toolbar/Index.vue +28 -79
  13. package/src/components/Toolbar/Items.vue +77 -0
  14. package/src/components/Toolbar/defaultExtensionComponents.ts +32 -0
  15. package/src/components/Toolbar/items/format.ts +0 -13
  16. package/src/components/Toolbar/items/media.ts +32 -23
  17. package/src/components/Toolbar/items/misc.ts +1 -1
  18. package/src/components/Toolbar/items/style.ts +43 -2
  19. package/src/components/Toolbar/items.ts +8 -7
  20. package/src/components/editorExtensions.ts +8 -10
  21. package/src/extensions/components/ImageDialog.vue +142 -0
  22. package/src/extensions/components/LinkDialog.vue +77 -36
  23. package/src/extensions/components/PreviewDialog.vue +0 -1
  24. package/src/extensions/components/ShowSourceDialog.vue +5 -3
  25. package/src/extensions/components/StyleColor.vue +177 -0
  26. package/src/extensions/components/TableBuilder.vue +4 -5
  27. package/src/extensions/image.ts +31 -0
  28. package/src/extensions/link.ts +24 -0
  29. package/src/extensions/preview.ts +2 -15
  30. package/src/extensions/view-source.ts +0 -3
  31. package/src/i18n/locales/de.json +46 -20
  32. package/src/i18n/locales/en.json +31 -5
  33. package/src/i18n/locales/es.json +38 -12
  34. package/src/i18n/locales/fr.json +49 -23
  35. package/src/i18n/locales/it.json +42 -16
  36. package/src/i18n/locales/pl.json +46 -19
  37. package/src/i18n/locales/ru.json +30 -4
  38. package/src/i18n/locales/ua.json +30 -4
  39. package/src/index.ts +0 -1
  40. package/src/types/overridable-extensions.ts +6 -0
@@ -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
+ }
@@ -55,19 +55,6 @@ export function getFormatItems(editor: Editor) {
55
55
  attrs: {
56
56
  click: () => editor.chain().focus().toggleUnderline().run()
57
57
  }
58
- },
59
- highlight: {
60
- name: 'highlight',
61
- tooltip: 'format.highlight',
62
- icon: mdi.mdiMarker,
63
- enabled: true,
64
- props: {
65
- disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
66
- color: computed(() => editor.isActive('highlight') ? 'primary' : ''),
67
- },
68
- attrs: {
69
- click: () => editor.chain().focus().toggleHighlight().run()
70
- }
71
58
  }
72
59
  }
73
60
  }
@@ -1,13 +1,13 @@
1
1
  import * as mdi from "@mdi/js";
2
2
  import { Editor } from "@tiptap/vue-3";
3
3
  import TableBuilder from "@tiptapify/extensions/components/TableBuilder.vue";
4
- import { computed, markRaw, Ref } from "vue";
4
+ import { computed, markRaw } from "vue";
5
5
 
6
- export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
6
+ export function getMediaItems(editor: Editor) {
7
7
  return {
8
8
  link: {
9
- name: 'format.link',
10
- tooltip: 'format.link',
9
+ name: 'media.link',
10
+ tooltip: 'media.link',
11
11
  icon: computed(() => editor.isActive('link') ? mdi.mdiLinkOff : mdi.mdiLink),
12
12
  enabled: true,
13
13
  props: {
@@ -15,16 +15,25 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
15
15
  disabled: computed(() => editor.isActive('code') || editor.isActive('codeBlock')),
16
16
  },
17
17
  attrs: {
18
- click: computed(() => {
19
- return editor.isActive('link')
20
- ? editor.chain().focus().unsetLink().run
21
- : toolbarLinkButton?.value?.open
22
- })
18
+ click: () => editor.commands.showLink()
19
+ }
20
+ },
21
+ image: {
22
+ name: 'media.image',
23
+ tooltip: 'media.image',
24
+ icon: mdi.mdiImage,
25
+ enabled: true,
26
+ props: {
27
+ color: computed(() => editor.isActive('image') ? 'primary' : ''),
28
+ disabled: computed(() => editor.isActive('code') || editor.isActive('codeBlock')),
29
+ },
30
+ attrs: {
31
+ click: () => editor.commands.showTiptapifyImage()
23
32
  }
24
33
  },
25
34
  table: {
26
35
  name: 'tables',
27
- tooltip: 'format.tables.table',
36
+ tooltip: 'media.tables.table',
28
37
  icon: mdi.mdiTable,
29
38
  modelValue: false,
30
39
  enabled: true,
@@ -35,7 +44,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
35
44
  children: [
36
45
  {
37
46
  name: 'insert table',
38
- tooltip: 'format.tables.insertTable',
47
+ tooltip: 'media.tables.insertTable',
39
48
  icon: mdi.mdiTablePlus,
40
49
  enabled: true,
41
50
  props: {
@@ -49,8 +58,8 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
49
58
  component: markRaw(TableBuilder),
50
59
  },
51
60
  {
52
- name: 'insert table',
53
- tooltip: 'format.tables.deleteTable',
61
+ name: 'delete table',
62
+ tooltip: 'media.tables.deleteTable',
54
63
  icon: mdi.mdiTableMinus,
55
64
  enabled: true,
56
65
  props: {
@@ -62,7 +71,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
62
71
  },
63
72
  {
64
73
  name: 'table row',
65
- tooltip: 'format.tables.row',
74
+ tooltip: 'media.tables.row',
66
75
  icon: mdi.mdiTableRow,
67
76
  enabled: true,
68
77
  props: {
@@ -80,7 +89,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
80
89
  children: [
81
90
  {
82
91
  name: 'insert row before',
83
- tooltip: 'format.tables.insertRowBefore',
92
+ tooltip: 'media.tables.insertRowBefore',
84
93
  icon: mdi.mdiTableRowPlusBefore,
85
94
  enabled: true,
86
95
  props: {
@@ -92,7 +101,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
92
101
  },
93
102
  {
94
103
  name: 'insert row after',
95
- tooltip: 'format.tables.insertRowAfter',
104
+ tooltip: 'media.tables.insertRowAfter',
96
105
  icon: mdi.mdiTableRowPlusAfter,
97
106
  enabled: true,
98
107
  props: {
@@ -104,7 +113,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
104
113
  },
105
114
  {
106
115
  name: 'delete row',
107
- tooltip: 'format.tables.deleteRow',
116
+ tooltip: 'media.tables.deleteRow',
108
117
  icon: mdi.mdiTableRowRemove,
109
118
  enabled: true,
110
119
  props: {
@@ -118,7 +127,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
118
127
  },
119
128
  {
120
129
  name: 'column',
121
- tooltip: 'format.tables.col',
130
+ tooltip: 'media.tables.col',
122
131
  icon: mdi.mdiTableColumn,
123
132
  enabled: true,
124
133
  props: {
@@ -136,7 +145,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
136
145
  children: [
137
146
  {
138
147
  name: 'insert col before',
139
- tooltip: 'format.tables.insertColBefore',
148
+ tooltip: 'media.tables.insertColBefore',
140
149
  icon: mdi.mdiTableColumnPlusBefore,
141
150
  enabled: true,
142
151
  props: {
@@ -148,7 +157,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
148
157
  },
149
158
  {
150
159
  name: 'insert column after',
151
- tooltip: 'format.tables.insertColAfter',
160
+ tooltip: 'media.tables.insertColAfter',
152
161
  icon: mdi.mdiTableColumnPlusAfter,
153
162
  enabled: true,
154
163
  props: {
@@ -160,7 +169,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
160
169
  },
161
170
  {
162
171
  name: 'delete column',
163
- tooltip: 'format.tables.deleteCol',
172
+ tooltip: 'media.tables.deleteCol',
164
173
  icon: mdi.mdiTableColumnRemove,
165
174
  enabled: true,
166
175
  props: {
@@ -174,7 +183,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
174
183
  },
175
184
  {
176
185
  name: 'merge cells',
177
- tooltip: 'format.tables.mergeCells',
186
+ tooltip: 'media.tables.mergeCells',
178
187
  icon: mdi.mdiTableMergeCells,
179
188
  enabled: true,
180
189
  props: {
@@ -186,7 +195,7 @@ export function getMediaItems(editor: Editor, toolbarLinkButton: Ref) {
186
195
  },
187
196
  {
188
197
  name: 'split cell',
189
- tooltip: 'format.tables.splitCell',
198
+ tooltip: 'media.tables.splitCell',
190
199
  icon: mdi.mdiTableSplitCell,
191
200
  enabled: true,
192
201
  props: {
@@ -1,6 +1,6 @@
1
1
  import * as mdi from "@mdi/js";
2
2
  import { Editor } from "@tiptap/vue-3";
3
- import { computed, Ref } from "vue";
3
+ import { computed } from "vue";
4
4
 
5
5
  export function getMiscItems(editor: Editor) {
6
6
  return {
@@ -1,14 +1,15 @@
1
1
  import * as mdi from "@mdi/js";
2
2
  import { Editor } from "@tiptap/vue-3";
3
3
  import { fonts } from "@tiptapify/components/Toolbar/fonts";
4
- import { computed, ref } from "vue";
4
+ import StyleColor from "@tiptapify/extensions/components/StyleColor.vue";
5
+ import { computed, markRaw, ref } from "vue";
5
6
 
6
7
  interface MDIIcons {
7
8
  [key: string]: string
8
9
  }
9
10
  const mdiIcons = mdi as MDIIcons
10
11
 
11
- export function getStyleItems(editor: Editor, fontMeasure: string, customHeadingLevels: Array<number> = []) {
12
+ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, customHeadingLevels: Array<number> = []) {
12
13
  const headingLevels = ref([1, 2, 3, 4, 5, 6])
13
14
  if (customHeadingLevels.length) {
14
15
  customHeadingLevels.forEach(level => {
@@ -141,6 +142,46 @@ export function getStyleItems(editor: Editor, fontMeasure: string, customHeading
141
142
  }
142
143
  }
143
144
  })
145
+ },
146
+ highlight: {
147
+ name: 'highlight',
148
+ tooltip: 'style.color.highlight',
149
+ icon: mdi.mdiFormatColorFill,
150
+ icon2: mdi.mdiColorHelper,
151
+ enabled: true,
152
+ icon2Props: {
153
+ color: computed(() => {
154
+ const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
155
+ return editor.getAttributes('highlight').color || defaultColor
156
+ }),
157
+ style: 'filter: drop-shadow(rgba(0, 0, 0, .75) 1px 1px 2px);'
158
+ },
159
+ component: markRaw(StyleColor),
160
+ componentProps: {
161
+ fontColor: false,
162
+ backgroundColor: true,
163
+ color: computed(() => editor.getAttributes('highlight').color || ''),
164
+ }
165
+ },
166
+ color: {
167
+ name: 'color',
168
+ tooltip: 'style.color.text',
169
+ icon: mdi.mdiFormatColorText,
170
+ icon2: mdi.mdiColorHelper,
171
+ enabled: true,
172
+ icon2Props: {
173
+ color: computed(() => {
174
+ const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
175
+ return editor.getAttributes('textStyle').color || defaultColor
176
+ }),
177
+ style: 'filter: drop-shadow(rgba(0, 0, 0, .75) 1px 1px 2px);'
178
+ },
179
+ component: markRaw(StyleColor),
180
+ componentProps: {
181
+ fontColor: true,
182
+ backgroundColor: false,
183
+ color: computed(() => editor.getAttributes('textStyle').color || ''),
184
+ }
144
185
  }
145
186
  }
146
187
  }
@@ -6,7 +6,7 @@ import { getListItems } from "@tiptapify/components/Toolbar/items/list";
6
6
  import { getMediaItems } from "@tiptapify/components/Toolbar/items/media";
7
7
  import { getMiscItems } from "@tiptapify/components/Toolbar/items/misc";
8
8
  import { getStyleItems } from "@tiptapify/components/Toolbar/items/style";
9
- import { ComputedRef, Ref, ref } from "vue";
9
+ import { ComputedRef, ref } from "vue";
10
10
 
11
11
  interface ToolbarItemAttrs {
12
12
  [key: string]: Function | any
@@ -20,12 +20,15 @@ export interface ToolbarItem {
20
20
  name: string|number,
21
21
  tooltip: string,
22
22
  icon: string|ComputedRef<string>,
23
+ icon2?: string|ComputedRef<string>,
23
24
  noI18n?: boolean,
24
25
  enabled: boolean,
25
26
  component?: any,
26
27
  modelValue?: any,
27
28
  group?: boolean,
28
29
  toggle?: boolean,
30
+ icon2Props?: ToolbarItemProps,
31
+ componentProps?: ToolbarItemProps,
29
32
  props?: ToolbarItemProps,
30
33
  attrs?: ToolbarItemAttrs,
31
34
  children?: ToolbarItems|ToolbarItem[],
@@ -47,26 +50,24 @@ export interface ToolbarItemSections {
47
50
 
48
51
  export function toolbarItems(
49
52
  editor: any,
53
+ theme: any,
50
54
  fontMeasure: string,
51
55
  items: { list: Array<string>, exclude: boolean },
52
- customHeadingLevels: Array<number>,
53
- toolbarLinkButton: Ref,
56
+ customHeadingLevels: Array<number>
54
57
  ): ToolbarItemSections {
55
- const styleItems = ref(getStyleItems(editor.value, fontMeasure, customHeadingLevels))
58
+ const styleItems = ref(getStyleItems(editor.value, theme, fontMeasure, customHeadingLevels))
56
59
  const formatItems = ref(getFormatItems(editor.value))
57
60
  const formatExtraItems = ref(getFormatExtraItems(editor.value))
58
61
  const alignmentItems = ref(getAlignmentItems(editor.value))
59
62
  const listItems = ref(getListItems(editor.value))
60
63
  const actionsItems = ref(getActionsItems(editor.value))
61
64
  const miscItems = ref(getMiscItems(editor.value))
62
- const mediaItems = ref(getMediaItems(editor.value, toolbarLinkButton))
65
+ const mediaItems = ref(getMediaItems(editor.value))
63
66
 
64
67
  const allMenuItems: ToolbarItemSections = {
65
68
  /**
66
69
  * todo
67
70
  *
68
- * font color, backgroundcolor
69
- * tables
70
71
  * media (image, video)
71
72
  */
72
73
  style: { group: true, items: styleItems.value },
@@ -23,7 +23,8 @@ 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
25
 
26
- import { Link } from '@tiptap/extension-link'
26
+ import { TiptapifyLink } from '@tiptapify/extensions/link'
27
+ import { TiptapifyImage } from '@tiptapify/extensions/image'
27
28
  import CodeBlockComponent from '@tiptapify/components/CodeBlockComponent.vue'
28
29
  import { ViewSource } from '@tiptapify/extensions/view-source'
29
30
  import { Preview } from '@tiptapify/extensions/preview'
@@ -68,12 +69,13 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
68
69
  Dropcursor,
69
70
  Typography,
70
71
  Underline,
71
- Highlight,
72
- Link.configure({
72
+ Highlight.configure({ multicolor: true }),
73
+ TiptapifyLink.configure({
73
74
  openOnClick: false,
74
- defaultProtocol: 'https',
75
+ defaultProtocol: 'https'
75
76
  }),
76
77
  Image,
78
+ TiptapifyImage,
77
79
  Superscript,
78
80
  Subscript,
79
81
  TableKit,
@@ -87,12 +89,8 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
87
89
  },
88
90
  })
89
91
  .configure({ lowlight }),
90
- Selection.configure({
91
- className: 'selection',
92
- }),
93
- TextAlign.configure({
94
- types: ['heading', 'paragraph'],
95
- }),
92
+ Selection.configure({ className: 'selection' }),
93
+ TextAlign.configure({ types: ['heading', 'paragraph'] }),
96
94
  Placeholder.configure({ placeholder }),
97
95
  CharacterCount,
98
96
  ViewSource,
@@ -0,0 +1,142 @@
1
+ <script setup lang="ts">
2
+
3
+ import * as mdi from '@mdi/js'
4
+ import { Editor } from "@tiptap/vue-3";
5
+
6
+ import { useI18n } from 'vue-i18n'
7
+ import { computed, inject, onMounted, onUnmounted, Ref, ref } from 'vue'
8
+
9
+ import helpers from '@tiptapify/utils/helpers'
10
+
11
+ defineProps({
12
+ variantBtn: { type: String, default() { return 'elevated' }},
13
+ variantField: { type: String, default() { return 'solo' }}
14
+ })
15
+
16
+ const { ucFirst } = helpers
17
+
18
+ const editor = inject('tiptapifyEditor') as Ref<Editor>
19
+ const { t } = useI18n()
20
+
21
+ const generateImageAttrs = () => ({
22
+ src: '',
23
+ alt: '',
24
+ height: null,
25
+ width: null
26
+ })
27
+
28
+ const attrs = ref(generateImageAttrs())
29
+
30
+ const dialog = ref<boolean>(false)
31
+
32
+ const isDisabled = computed(() => {
33
+ const { src } = attrs.value
34
+ return !src
35
+ })
36
+
37
+ function apply() {
38
+ let { src, alt, width, height } = attrs.value
39
+
40
+ const imageOptions: { src: string, alt: string, width?: number, height?: number} = {
41
+ src,
42
+ alt
43
+ }
44
+
45
+ if (width) {
46
+ imageOptions.width = width
47
+ }
48
+
49
+ if (height) {
50
+ imageOptions.height = height
51
+ }
52
+
53
+ if (src) {
54
+ editor.value.chain().focus().setImage(imageOptions).run()
55
+ }
56
+
57
+ close()
58
+ }
59
+
60
+ function clear() {
61
+ editor.value.commands.deleteSelection()
62
+
63
+ close()
64
+ }
65
+
66
+ function close() {
67
+ dialog.value = false
68
+
69
+ attrs.value = generateImageAttrs()
70
+ }
71
+
72
+ const showTiptapifyImage = (event: CustomEvent) => {
73
+ attrs.value.src = event.detail.image?.src
74
+ attrs.value.alt = event.detail.image?.alt
75
+ attrs.value.width = event.detail.image?.width
76
+ attrs.value.height = event.detail.image?.height
77
+
78
+ dialog.value = true;
79
+ }
80
+
81
+ onMounted(() => {
82
+ window.addEventListener('tiptapify-show-tiptapifyImage', showTiptapifyImage as EventListener)
83
+ })
84
+
85
+ onUnmounted(() => {
86
+ window.removeEventListener('tiptapify-show-tiptapifyImage', showTiptapifyImage as EventListener)
87
+ })
88
+ </script>
89
+
90
+ <template>
91
+ <VDialog v-model="dialog" max-width="800" absolute @click:outside="close">
92
+ <VCard>
93
+ <VToolbar class="px-6" density="compact">
94
+ <span class="headline">{{ ucFirst(t('dialog.image.title')) }}</span>
95
+
96
+ <VSpacer />
97
+
98
+ <VBtn class="mx-0" icon @click="close">
99
+ <VIcon :icon="mdi.mdiClose" />
100
+ </VBtn>
101
+ </VToolbar>
102
+
103
+ <VCardText>
104
+ <VRow>
105
+ <VCol cols="12">
106
+ <VTextField v-model="attrs.src" :variant="variantField" :label="ucFirst(t('dialog.image.src'))" />
107
+ </VCol>
108
+
109
+ <VCol cols="12" md="6">
110
+ <VTextField v-model="attrs.alt" :variant="variantField" :label="ucFirst(t('dialog.image.alt'))" />
111
+ </VCol>
112
+
113
+ <VCol cols="12" md="3">
114
+ <VTextField v-model="attrs.width" type="number" :variant="variantField" :precision="0" :min="1" :label="ucFirst(t('dialog.image.width'))" />
115
+ </VCol>
116
+
117
+ <VCol cols="12" md="3">
118
+ <VTextField v-model="attrs.height" type="number" :variant="variantField" :precision="0" :min="1" :label="ucFirst(t('dialog.image.height'))" />
119
+ </VCol>
120
+ </VRow>
121
+ </VCardText>
122
+
123
+ <VCardActions>
124
+ <VRow>
125
+ <VCol class="d-flex justify-start">
126
+ <VBtn color="warning" v-if="editor.isActive('image')" :variant="variantBtn" :disabled="isDisabled" @click="clear">
127
+ {{ ucFirst(t('dialog.clear')) }}
128
+ </VBtn>
129
+ </VCol>
130
+ <VCol class="d-flex justify-end">
131
+ <VBtn :variant="variantBtn" @click="close" class="mr-2">
132
+ {{ ucFirst(t('dialog.close')) }}
133
+ </VBtn>
134
+ <VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
135
+ {{ ucFirst(t('dialog.apply')) }}
136
+ </VBtn>
137
+ </VCol>
138
+ </VRow>
139
+ </VCardActions>
140
+ </VCard>
141
+ </VDialog>
142
+ </template>