tiptapify 0.0.9 → 0.0.10

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tiptapify",
3
3
  "types": "./index.d.ts",
4
- "version": "0.0.9",
4
+ "version": "0.0.10",
5
5
  "description": "Tiptap3 editor with Vuetify3 menu implementation",
6
6
  "exports": {
7
7
  ".": {
@@ -94,7 +94,7 @@
94
94
  "highlight.js": "^11.11.1",
95
95
  "linkifyjs": "^4.3.1",
96
96
  "lowlight": "^3.3.0",
97
- "vue-i18n": "^11.1.6"
97
+ "vue-i18n": "^11.1.9"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "@mdi/js": "^7.4.47",
@@ -104,17 +104,17 @@
104
104
  "devDependencies": {
105
105
  "@intlify/unplugin-vue-i18n": "^6.0.8",
106
106
  "@rollup/plugin-alias": "^5.1.1",
107
- "@types/node": "^22.15.32",
107
+ "@types/node": "^22.16.4",
108
108
  "@vitejs/plugin-vue": "^5.2.4",
109
109
  "@vitejs/plugin-vue-jsx": "^4.2.0",
110
110
  "rollup-plugin-tsconfig-paths": "^1.5.2",
111
111
  "sass-embedded": "^1.89.2",
112
112
  "typescript": "^5.8.3",
113
- "unplugin-vue-components": "^28.7.0",
113
+ "unplugin-vue-components": "^28.8.0",
114
114
  "vite": "^6.3.5",
115
115
  "vite-plugin-vuetify": "^2.1.1",
116
116
  "vite-svg-loader": "^5.1.0",
117
117
  "vite-tsconfig-paths": "^5.1.4",
118
- "vue-tsc": "^2.2.10"
118
+ "vue-tsc": "^2.2.12"
119
119
  }
120
120
  }
@@ -4,25 +4,21 @@ import { useI18n } from "vue-i18n";
4
4
 
5
5
  import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
6
6
 
7
- import helpers from "@tiptapify/utils/helpers";
8
-
9
7
  defineProps({
10
8
  variant: { type: String, default () { return 'flat' }},
11
9
  toolbarItem: { type: Object as PropType<ToolbarItem>, default() { return {} }}
12
10
  })
13
11
 
14
12
  const { t } = useI18n();
15
-
16
- const { ucFirst } = helpers;
17
13
  </script>
18
14
 
19
15
  <template>
20
16
  <VBtn v-bind="toolbarItem?.props ?? {}" v-on="toolbarItem?.attrs ?? {}" size="32">
21
- <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
17
+ <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
22
18
 
23
19
  <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
24
20
  <span v-else class="menu-item-title">
25
- {{ ucFirst(t(toolbarItem.name)) }}
21
+ {{ t(toolbarItem.name) }}
26
22
  </span>
27
23
 
28
24
  <VIcon v-if="toolbarItem.icon2" v-bind="toolbarItem?.icon2Props ?? {}" :icon="toolbarItem.icon2" size="small" style="position: absolute;" />
@@ -2,12 +2,8 @@
2
2
  import { defineProps, PropType } from 'vue'
3
3
  import { useI18n } from "vue-i18n";
4
4
 
5
- import helpers from "@tiptapify/utils/helpers";
6
-
7
5
  import { ToolbarItem } from "@tiptapify/components/Toolbar/items";
8
6
 
9
- const { ucFirst } = helpers;
10
-
11
7
  defineProps({
12
8
  variant: { type: String, default () { return 'flat' }},
13
9
  nested: { type: Boolean, default () { return false }},
@@ -22,11 +18,11 @@ const { t } = useI18n();
22
18
  <VMenu v-model="toolbarItem.modelValue" v-bind="toolbarItem.props">
23
19
  <template v-if="!nested" #activator="{ props: menuProps }">
24
20
  <VBtn v-bind="{ ...menuProps, ...toolbarItem.props }" size="32">
25
- <VTooltip :text="ucFirst(t(toolbarItem.tooltip))" location="top" activator="parent" />
21
+ <VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
26
22
 
27
23
  <VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="small" />
28
24
  <span v-else class="menu-item-title">
29
- {{ ucFirst(t(toolbarItem.name)) }}
25
+ {{ t(toolbarItem.name) }}
30
26
  </span>
31
27
  </VBtn>
32
28
  </template>
@@ -47,7 +43,7 @@ const { t } = useI18n();
47
43
  v-bind="item.props ?? {}"
48
44
  v-on="item?.attrs ?? {}"
49
45
  >
50
- <VTooltip v-if="item.tooltip" :text="ucFirst(t(item.tooltip))" location="top" activator="parent" />
46
+ <VTooltip v-if="item.tooltip" :text="t(item.tooltip)" location="top" activator="parent" />
51
47
 
52
48
  <VIcon v-if="item.icon" :icon="item.icon" size="small" />
53
49
 
@@ -56,7 +52,7 @@ const { t } = useI18n();
56
52
  {{ item.name }}
57
53
  </template>
58
54
  <template v-else>
59
- {{ ucFirst(t(item.toggle)) }}
55
+ {{ t(item.toggle) }}
60
56
  </template>
61
57
  </span>
62
58
 
@@ -25,11 +25,11 @@ const props = defineProps({
25
25
 
26
26
  const editor = inject('tiptapifyEditor') as Ref<Editor>
27
27
 
28
- const theme = useTheme()
28
+ const appTheme = useTheme()
29
29
 
30
30
  const items = toolbarItems(
31
31
  editor,
32
- theme,
32
+ appTheme,
33
33
  computed(() => props.fontMeasure).value,
34
34
  { list: computed(() => props.items).value, exclude: computed(() => props.itemsExclude).value },
35
35
  computed(() => props.headingLevels).value
@@ -30,19 +30,6 @@ export function getFormatItems(editor: Editor) {
30
30
  click: () => editor.chain().focus().toggleItalic().run()
31
31
  }
32
32
  },
33
- strike: {
34
- name: 'strike',
35
- tooltip: 'format.strike',
36
- icon: mdi.mdiFormatStrikethroughVariant,
37
- enabled: true,
38
- props: {
39
- disabled: computed(() => !editor.can().chain().focus().toggleStrike().run()),
40
- color: computed(() => editor.isActive('strike') ? 'primary' : ''),
41
- },
42
- attrs: {
43
- click: () => editor.chain().focus().toggleStrike().run()
44
- }
45
- },
46
33
  underline: {
47
34
  name: 'underline',
48
35
  tooltip: 'format.underline',
@@ -55,6 +42,19 @@ export function getFormatItems(editor: Editor) {
55
42
  attrs: {
56
43
  click: () => editor.chain().focus().toggleUnderline().run()
57
44
  }
45
+ },
46
+ strike: {
47
+ name: 'strike',
48
+ tooltip: 'format.strike',
49
+ icon: mdi.mdiFormatStrikethroughVariant,
50
+ enabled: true,
51
+ props: {
52
+ disabled: computed(() => !editor.can().chain().focus().toggleStrike().run()),
53
+ color: computed(() => editor.isActive('strike') ? 'primary' : ''),
54
+ },
55
+ attrs: {
56
+ click: () => editor.chain().focus().toggleStrike().run()
57
+ }
58
58
  }
59
59
  }
60
60
  }
@@ -62,7 +62,7 @@ export function getFormatExtraItems(editor: Editor) {
62
62
  icon: mdi.mdiCommentQuote,
63
63
  enabled: true,
64
64
  props: {
65
- disabled: computed(() => !editor.can().chain().focus().toggleBlockquote().run()),
65
+ disabled: computed(() => !editor.can().chain().focus().toggleBlockquote().run() || editor.isActive('codeBlock') || editor.isActive('code')),
66
66
  color: computed(() => editor.isActive('blockquote') ? 'primary' : ''),
67
67
  },
68
68
  attrs: {
@@ -73,6 +73,9 @@ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, c
73
73
  icon: mdi.mdiFormatFont,
74
74
  modelValue: false,
75
75
  enabled: true,
76
+ props: {
77
+ disabled: computed(() => !editor.can().chain().focus().unsetFontFamily().run()),
78
+ },
76
79
  attrs: {
77
80
  click: () => editor.chain().focus().unsetFontFamily().run()
78
81
  },
@@ -99,6 +102,9 @@ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, c
99
102
  icon: mdi.mdiFormatSize,
100
103
  modelValue: false,
101
104
  enabled: true,
105
+ props: {
106
+ disabled: computed(() => !editor.can().chain().focus().unsetFontSize().run()),
107
+ },
102
108
  attrs: {
103
109
  click: () => editor.chain().focus().unsetFontSize().run()
104
110
  },
@@ -124,6 +130,9 @@ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, c
124
130
  icon: mdi.mdiFormatLineHeight,
125
131
  modelValue: null,
126
132
  enabled: true,
133
+ props: {
134
+ disabled: computed(() => !editor.can().chain().focus().unsetLineHeight().run()),
135
+ },
127
136
  attrs: {
128
137
  click: () => editor.chain().focus().unsetLineHeight().run()
129
138
  },
@@ -149,7 +158,11 @@ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, c
149
158
  icon: mdi.mdiFormatColorFill,
150
159
  icon2: mdi.mdiColorHelper,
151
160
  enabled: true,
161
+ props: {
162
+ disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
163
+ },
152
164
  icon2Props: {
165
+ disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
153
166
  color: computed(() => {
154
167
  const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
155
168
  return editor.getAttributes('highlight').color || defaultColor
@@ -169,7 +182,11 @@ export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, c
169
182
  icon: mdi.mdiFormatColorText,
170
183
  icon2: mdi.mdiColorHelper,
171
184
  enabled: true,
185
+ props: {
186
+ disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
187
+ },
172
188
  icon2Props: {
189
+ disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
173
190
  color: computed(() => {
174
191
  const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
175
192
  return editor.getAttributes('textStyle').color || defaultColor
@@ -0,0 +1,141 @@
1
+ <script lang="ts" setup>
2
+
3
+ import * as mdi from "@mdi/js";
4
+ import { nextTick, ref, watch } from "vue";
5
+ import { useI18n } from "vue-i18n";
6
+
7
+ const props = defineProps({
8
+ module: String,
9
+ fullscreen: { type: Boolean, default () { return false } },
10
+ maxWidth: { type: Number, default () { return 800 } },
11
+ })
12
+
13
+ const { t } = useI18n();
14
+
15
+ defineExpose({ open, close })
16
+ const emits = defineEmits(['closeDialog'])
17
+
18
+ const dialog = ref<boolean>(false)
19
+ const movableHandler = ref(null)
20
+
21
+ function open() {
22
+ dialog.value = true
23
+ }
24
+
25
+ function close() {
26
+ dialog.value = false
27
+ }
28
+
29
+ function emitClose() {
30
+ emits('closeDialog')
31
+
32
+ close()
33
+ }
34
+
35
+ function dragElement(trigger: HTMLElement, container: HTMLElement) {
36
+ const coordinates = {
37
+ moveX: 0,
38
+ moveY: 0,
39
+ cursorX: 0,
40
+ cursorY: 0,
41
+ }
42
+
43
+ trigger.onmousedown = dragMouseDown
44
+
45
+ function dragMouseDown(e: MouseEvent) {
46
+ e.preventDefault()
47
+
48
+ coordinates.cursorX = e.clientX
49
+ coordinates.cursorY = e.clientY
50
+
51
+ document.onmouseup = closeDragElement
52
+ document.onmousemove = elementDrag
53
+ }
54
+
55
+ function elementDrag(e: MouseEvent) {
56
+ e.preventDefault();
57
+
58
+ coordinates.moveX = coordinates.cursorX - e.clientX
59
+ coordinates.moveY = coordinates.cursorY - e.clientY
60
+ coordinates.cursorX = e.clientX
61
+ coordinates.cursorY = e.clientY
62
+
63
+ const parentOffsetLeft = container.parentNode.offsetLeft
64
+ const parentOffsetTop = container.parentNode.offsetTop
65
+
66
+ let left = container.offsetLeft - coordinates.moveX
67
+ if (left < (parentOffsetLeft * -1)) {
68
+ left = (parentOffsetLeft * -1)
69
+ }
70
+ if (left >= parentOffsetLeft) {
71
+ left = parentOffsetLeft
72
+ }
73
+
74
+ let top = container.offsetTop - coordinates.moveY
75
+ if (top < (parentOffsetTop * -1)) {
76
+ top = (parentOffsetTop * -1)
77
+ }
78
+ if (top >= parentOffsetTop) {
79
+ top = parentOffsetTop
80
+ }
81
+
82
+ container.style.left = `${left}px`
83
+ container.style.top = `${top}px`
84
+ }
85
+
86
+ function closeDragElement() {
87
+ document.onmouseup = null
88
+ document.onmousemove = null
89
+ }
90
+ }
91
+
92
+ watch(() => dialog.value, async () => {
93
+ await nextTick()
94
+
95
+ if (!movableHandler.value) {
96
+ return
97
+ }
98
+
99
+ if (dialog.value && !props.fullscreen) {
100
+ dragElement(movableHandler.value.$el as HTMLElement, movableHandler.value.$el.parentNode as HTMLElement)
101
+ }
102
+ })
103
+ </script>
104
+
105
+ <template>
106
+ <VDialog v-model="dialog" :max-width="maxWidth" :fullscreen="fullscreen" absolute @click:outside="emitClose">
107
+ <VCard>
108
+ <VCardTitle ref="movableHandler" :class="`d-flex ${!fullscreen ? 'tiptapify-movable-handler' : ''}`" style="user-select: none;">
109
+ <VLabel>
110
+ {{ t(`dialog.${module}.title`) }}
111
+ </VLabel>
112
+
113
+ <VSpacer />
114
+
115
+ <VBtn density="compact" class="tiptapify-dialog-close" variant="elevated" elevation="4" icon @click="emitClose">
116
+ <VIcon size="x-small" :icon="mdi.mdiClose" />
117
+ </VBtn>
118
+ </VCardTitle>
119
+
120
+ <VDivider />
121
+
122
+ <slot name="content" />
123
+
124
+ <slot name="actions" />
125
+ </VCard>
126
+ </VDialog>
127
+ </template>
128
+
129
+ <style lang="scss" scoped>
130
+ :deep(.v-overlay__content) {
131
+ position: fixed;
132
+ }
133
+
134
+ .tiptapify-movable-handler, :deep(.tiptapify-movable-handler > *) {
135
+ cursor: move;
136
+ }
137
+
138
+ .tiptapify-dialog-close:hover {
139
+ cursor: pointer;
140
+ }
141
+ </style>
@@ -1,20 +1,16 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import * as mdi from '@mdi/js'
4
3
  import { Editor } from "@tiptap/vue-3";
4
+ import Dialog from "@tiptapify/components/UI/Dialog.vue";
5
5
 
6
6
  import { useI18n } from 'vue-i18n'
7
7
  import { computed, inject, onMounted, onUnmounted, Ref, ref } from 'vue'
8
8
 
9
- import helpers from '@tiptapify/utils/helpers'
10
-
11
9
  defineProps({
12
10
  variantBtn: { type: String, default() { return 'elevated' }},
13
11
  variantField: { type: String, default() { return 'solo' }}
14
12
  })
15
13
 
16
- const { ucFirst } = helpers
17
-
18
14
  const editor = inject('tiptapifyEditor') as Ref<Editor>
19
15
  const { t } = useI18n()
20
16
 
@@ -27,7 +23,7 @@ const generateImageAttrs = () => ({
27
23
 
28
24
  const attrs = ref(generateImageAttrs())
29
25
 
30
- const dialog = ref<boolean>(false)
26
+ const dialog = ref(null)
31
27
 
32
28
  const isDisabled = computed(() => {
33
29
  const { src } = attrs.value
@@ -64,7 +60,7 @@ function clear() {
64
60
  }
65
61
 
66
62
  function close() {
67
- dialog.value = false
63
+ dialog.value.close()
68
64
 
69
65
  attrs.value = generateImageAttrs()
70
66
  }
@@ -75,7 +71,7 @@ const showTiptapifyImage = (event: CustomEvent) => {
75
71
  attrs.value.width = event.detail.image?.width
76
72
  attrs.value.height = event.detail.image?.height
77
73
 
78
- dialog.value = true;
74
+ dialog.value.open()
79
75
  }
80
76
 
81
77
  onMounted(() => {
@@ -88,55 +84,47 @@ onUnmounted(() => {
88
84
  </script>
89
85
 
90
86
  <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
-
87
+ <Dialog ref="dialog" module="image" :max-width="800">
88
+ <template #content>
103
89
  <VCardText>
104
90
  <VRow>
105
91
  <VCol cols="12">
106
- <VTextField v-model="attrs.src" :variant="variantField" :label="ucFirst(t('dialog.image.src'))" />
92
+ <VTextField v-model="attrs.src" density="compact" variant="outlined" :label="t('dialog.image.src')" />
107
93
  </VCol>
108
94
 
109
95
  <VCol cols="12" md="6">
110
- <VTextField v-model="attrs.alt" :variant="variantField" :label="ucFirst(t('dialog.image.alt'))" />
96
+ <VTextField v-model="attrs.alt" density="compact" variant="outlined" :label="t('dialog.image.alt')" />
111
97
  </VCol>
112
98
 
113
99
  <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'))" />
100
+ <VTextField v-model="attrs.width" type="number" density="compact" variant="outlined" :precision="0" :min="1" :label="t('dialog.image.width')" />
115
101
  </VCol>
116
102
 
117
103
  <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'))" />
104
+ <VTextField v-model="attrs.height" type="number" density="compact" variant="outlined" :precision="0" :min="1" :label="t('dialog.image.height')" />
119
105
  </VCol>
120
106
  </VRow>
121
107
  </VCardText>
108
+ </template>
122
109
 
110
+ <template #actions>
123
111
  <VCardActions>
124
112
  <VRow>
125
113
  <VCol class="d-flex justify-start">
126
114
  <VBtn color="warning" v-if="editor.isActive('image')" :variant="variantBtn" :disabled="isDisabled" @click="clear">
127
- {{ ucFirst(t('dialog.clear')) }}
115
+ {{ t('dialog.clear') }}
128
116
  </VBtn>
129
117
  </VCol>
130
118
  <VCol class="d-flex justify-end">
131
119
  <VBtn :variant="variantBtn" @click="close" class="mr-2">
132
- {{ ucFirst(t('dialog.close')) }}
120
+ {{ t('dialog.close') }}
133
121
  </VBtn>
134
122
  <VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
135
- {{ ucFirst(t('dialog.apply')) }}
123
+ {{ t('dialog.apply') }}
136
124
  </VBtn>
137
125
  </VCol>
138
126
  </VRow>
139
127
  </VCardActions>
140
- </VCard>
141
- </VDialog>
128
+ </template>
129
+ </Dialog>
142
130
  </template>