tiptapify 0.2.4 → 0.2.6
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/README.md +1 -1
- package/dist/tiptapify.css +1 -1
- package/dist/tiptapify.mjs +74210 -54575
- package/dist/tiptapify.umd.js +87 -84
- package/index.d.ts +42 -2
- package/package.json +45 -45
- package/src/components/Tiptapify.vue +108 -9
- package/src/components/Toolbar/Index.vue +2 -2
- package/src/components/Toolbar/Items.vue +9 -2
- package/src/components/UI/TiptapifyDialog.vue +7 -1
- package/src/extensions/components/ai/Button.vue +1 -1
- package/src/extensions/components/ai/Dialog.vue +338 -27
- package/src/extensions/components/ai/backend.test.ts +314 -0
- package/src/extensions/components/ai/backend.ts +303 -0
- package/src/extensions/components/ai/charLimit.test.ts +55 -0
- package/src/extensions/components/ai/charLimit.ts +30 -0
- package/src/extensions/components/ai/characterCount.test.ts +27 -0
- package/src/extensions/components/media/iframe/Button.vue +1 -2
- package/src/extensions/components/media/iframe/IframeDialog.vue +36 -31
- package/src/extensions/components/media/image/Button.vue +1 -1
- package/src/extensions/components/media/link/Button.vue +1 -1
- package/src/extensions/components/media/link/LinkDialog.vue +19 -36
- package/src/extensions/components/media/video/Button.vue +1 -1
- package/src/extensions/components/media/video/VideoDialog.vue +17 -17
- package/src/extensions/components/misc/source/Button.vue +1 -1
- package/src/i18n/locales/ar.json +165 -159
- package/src/i18n/locales/bg.json +212 -0
- package/src/i18n/locales/ch.json +165 -159
- package/src/i18n/locales/cz.json +165 -159
- package/src/i18n/locales/de.json +165 -159
- package/src/i18n/locales/el.json +212 -0
- package/src/i18n/locales/en.json +166 -159
- package/src/i18n/locales/es.json +165 -159
- package/src/i18n/locales/et.json +212 -0
- package/src/i18n/locales/fi.json +165 -159
- package/src/i18n/locales/fr.json +165 -159
- package/src/i18n/locales/he.json +212 -0
- package/src/i18n/locales/hi.json +212 -0
- package/src/i18n/locales/hr.json +212 -0
- package/src/i18n/locales/hu.json +165 -159
- package/src/i18n/locales/id.json +212 -0
- package/src/i18n/locales/it.json +165 -159
- package/src/i18n/locales/ja.json +165 -159
- package/src/i18n/locales/ko.json +165 -159
- package/src/i18n/locales/la.json +165 -159
- package/src/i18n/locales/lt.json +165 -159
- package/src/i18n/locales/nl.json +165 -159
- package/src/i18n/locales/no.json +212 -0
- package/src/i18n/locales/pl.json +165 -159
- package/src/i18n/locales/pt-BR.json +212 -0
- package/src/i18n/locales/pt.json +165 -159
- package/src/i18n/locales/ro.json +212 -0
- package/src/i18n/locales/ru.json +165 -159
- package/src/i18n/locales/se.json +165 -159
- package/src/i18n/locales/sk.json +212 -0
- package/src/i18n/locales/sl.json +212 -0
- package/src/i18n/locales/sr.json +212 -0
- package/src/i18n/locales/th.json +165 -159
- package/src/i18n/locales/tr.json +165 -159
- package/src/i18n/locales/uk.json +165 -159
- package/src/i18n/locales/vi.json +165 -159
- package/src/index.ts +7 -0
- package/src/types/editor.ts +40 -2
- package/src/utils/validateHref.test.ts +68 -0
- package/src/utils/validateHref.ts +21 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { Editor } from '@tiptap/vue-3'
|
|
3
|
+
import { Document } from '@tiptap/extension-document'
|
|
4
|
+
import { Paragraph } from '@tiptap/extension-paragraph'
|
|
5
|
+
import { Text } from '@tiptap/extension-text'
|
|
6
|
+
import { CharacterCount } from '@tiptap/extensions'
|
|
7
|
+
|
|
8
|
+
function createEditor() {
|
|
9
|
+
return new Editor({
|
|
10
|
+
content: '<p>hello</p>',
|
|
11
|
+
extensions: [Document, Paragraph, Text, CharacterCount.configure({ limit: 100 })],
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('character count limit', () => {
|
|
16
|
+
it('rejects an insert that would exceed the character limit', () => {
|
|
17
|
+
const editor = createEditor()
|
|
18
|
+
const before = JSON.stringify(editor.getJSON())
|
|
19
|
+
|
|
20
|
+
editor.chain().focus().insertContent('a'.repeat(200)).run()
|
|
21
|
+
|
|
22
|
+
// The CharacterCount filterTransaction rejects the transaction, so the doc is unchanged
|
|
23
|
+
expect(JSON.stringify(editor.getJSON())).toBe(before)
|
|
24
|
+
|
|
25
|
+
editor.destroy()
|
|
26
|
+
})
|
|
27
|
+
})
|
|
@@ -35,8 +35,7 @@ const icon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" vie
|
|
|
35
35
|
<BtnIcon :icon="icon" />
|
|
36
36
|
</VBtn>
|
|
37
37
|
|
|
38
|
-
<IframeDialog ref="dialog" />
|
|
39
|
-
<!-- Dialog here -->
|
|
38
|
+
<IframeDialog ref="dialog" :variant-btn="variantBtn" />
|
|
40
39
|
</template>
|
|
41
40
|
|
|
42
41
|
<style lang="scss" scoped>
|
|
@@ -113,8 +113,8 @@ watch(() => attrs.value.src, () => {
|
|
|
113
113
|
<TiptapifyDialog ref="dialog" module="iframe" :title="t('dialog.iframe.dialog_title')" :max-width="800">
|
|
114
114
|
<template #content>
|
|
115
115
|
<VCardText>
|
|
116
|
-
<
|
|
117
|
-
<
|
|
116
|
+
<div class="tiptapify-dialog-grid">
|
|
117
|
+
<div class="tiptapify-dialog-col">
|
|
118
118
|
<VTextField
|
|
119
119
|
v-model="attrs.src"
|
|
120
120
|
density="compact"
|
|
@@ -122,23 +122,23 @@ watch(() => attrs.value.src, () => {
|
|
|
122
122
|
:label="t('dialog.iframe.src')"
|
|
123
123
|
:error-messages="srcInvalid ? t('dialog.iframe.src_invalid') : ''"
|
|
124
124
|
/>
|
|
125
|
-
</
|
|
125
|
+
</div>
|
|
126
126
|
|
|
127
|
-
<
|
|
128
|
-
<
|
|
129
|
-
<
|
|
127
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--6">
|
|
128
|
+
<div class="tiptapify-dialog-grid">
|
|
129
|
+
<div class="tiptapify-dialog-col">
|
|
130
130
|
<VTextField v-model="attrs.name" density="compact" variant="outlined" :label="t('dialog.iframe.name')" />
|
|
131
|
-
</
|
|
131
|
+
</div>
|
|
132
132
|
|
|
133
|
-
<
|
|
133
|
+
<div class="tiptapify-dialog-col">
|
|
134
134
|
<VTextField v-model="attrs.title" density="compact" variant="outlined" :label="t('dialog.iframe.title')" />
|
|
135
|
-
</
|
|
136
|
-
</
|
|
137
|
-
</
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
138
|
|
|
139
|
-
<
|
|
140
|
-
<
|
|
141
|
-
<
|
|
139
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--6">
|
|
140
|
+
<div class="tiptapify-dialog-grid">
|
|
141
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--6">
|
|
142
142
|
<VTextField
|
|
143
143
|
v-model="attrs.width"
|
|
144
144
|
type="number"
|
|
@@ -148,9 +148,9 @@ watch(() => attrs.value.src, () => {
|
|
|
148
148
|
:min="1"
|
|
149
149
|
:label="t('dialog.iframe.width')"
|
|
150
150
|
/>
|
|
151
|
-
</
|
|
151
|
+
</div>
|
|
152
152
|
|
|
153
|
-
<
|
|
153
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--6">
|
|
154
154
|
<VTextField
|
|
155
155
|
v-model="attrs.height"
|
|
156
156
|
type="number"
|
|
@@ -160,34 +160,39 @@ watch(() => attrs.value.src, () => {
|
|
|
160
160
|
:min="1"
|
|
161
161
|
:label="t('dialog.iframe.height')"
|
|
162
162
|
/>
|
|
163
|
-
</
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
<VSwitch
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<div class="tiptapify-dialog-col">
|
|
166
|
+
<VSwitch
|
|
167
|
+
v-model="attrs.frameborder"
|
|
168
|
+
density="compact"
|
|
169
|
+
:hide-details="true"
|
|
170
|
+
:label="t('dialog.iframe.frameborder')"
|
|
171
|
+
/>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
171
176
|
</VCardText>
|
|
172
177
|
</template>
|
|
173
178
|
|
|
174
179
|
<template #actions>
|
|
175
180
|
<VCardActions>
|
|
176
|
-
<
|
|
177
|
-
<
|
|
181
|
+
<div class="tiptapify-dialog-actions">
|
|
182
|
+
<div class="tiptapify-dialog-actions__start">
|
|
178
183
|
<VBtn v-if="editor.isActive('image')" color="warning" :variant="variantBtn" :disabled="isDisabled" @click="clear">
|
|
179
184
|
{{ t('dialog.clear') }}
|
|
180
185
|
</VBtn>
|
|
181
|
-
</
|
|
182
|
-
<
|
|
183
|
-
<VBtn :variant="variantBtn"
|
|
186
|
+
</div>
|
|
187
|
+
<div class="tiptapify-dialog-actions__end">
|
|
188
|
+
<VBtn :variant="variantBtn" @click="close">
|
|
184
189
|
{{ t('dialog.close') }}
|
|
185
190
|
</VBtn>
|
|
186
191
|
<VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
|
|
187
192
|
{{ t('dialog.apply') }}
|
|
188
193
|
</VBtn>
|
|
189
|
-
</
|
|
190
|
-
</
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
191
196
|
</VCardActions>
|
|
192
197
|
</template>
|
|
193
198
|
</TiptapifyDialog>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Editor } from '@tiptap/vue-3'
|
|
4
4
|
import defaults from '@tiptapify/constants/defaults'
|
|
5
5
|
import { variantBtnTypes, variantFieldTypes } from '@tiptapify/types/editor'
|
|
6
|
+
import { isValidHref } from '@tiptapify/utils/validateHref'
|
|
6
7
|
|
|
7
8
|
import { computed, inject, onMounted, onUnmounted, PropType, Ref, ref, useTemplateRef, watch } from 'vue'
|
|
8
9
|
|
|
@@ -86,25 +87,7 @@ onUnmounted(() => {
|
|
|
86
87
|
})
|
|
87
88
|
|
|
88
89
|
watch(() => attrs.value.href, () => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const regexHrefProto = 'https?:\\/\\/'
|
|
92
|
-
const regexHrefAuth = `([${azAZ09}]+(:[${azAZ09}]+)?@)?`
|
|
93
|
-
const regexHrefDomain = `[${azAZ09}]+(\\.[${azAZ09}]+(-?[${azAZ09}]+)?)+`
|
|
94
|
-
const regexHrefPath = `(\\/[${azAZ09}\\-]+)*`
|
|
95
|
-
const regexHrefFragment = '(#[^\\s]*)?'
|
|
96
|
-
const regexHrefQueryParam = `(\\?[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)?`
|
|
97
|
-
const regexHrefQueryParamExtra = `(&[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)*`
|
|
98
|
-
const regexHref = `${regexHrefProto}${regexHrefAuth}${regexHrefDomain}${regexHrefPath}${regexHrefFragment}${regexHrefQueryParam}${regexHrefQueryParamExtra}`
|
|
99
|
-
|
|
100
|
-
const regexMailto = `mailto:\\w+@[${azAZ09}]+(\\.[${azAZ09}]+)*`
|
|
101
|
-
const regexTel = 'tel:\\+?[0-9]+'
|
|
102
|
-
|
|
103
|
-
const regexAll = [regexHref, regexMailto, regexTel].join('|')
|
|
104
|
-
|
|
105
|
-
const regex = new RegExp(`^(${regexAll})$`, 'i')
|
|
106
|
-
|
|
107
|
-
hrefInvalid.value = (attrs.value.href || '') !== '' && !regex.test(attrs.value.href)
|
|
90
|
+
hrefInvalid.value = (attrs.value.href || '') !== '' && !isValidHref(attrs.value.href)
|
|
108
91
|
})
|
|
109
92
|
</script>
|
|
110
93
|
|
|
@@ -112,8 +95,8 @@ watch(() => attrs.value.href, () => {
|
|
|
112
95
|
<TiptapifyDialog ref="dialog" module="link">
|
|
113
96
|
<template #content>
|
|
114
97
|
<VCardText>
|
|
115
|
-
<
|
|
116
|
-
<
|
|
98
|
+
<div class="tiptapify-dialog-grid">
|
|
99
|
+
<div class="tiptapify-dialog-col">
|
|
117
100
|
<VTextField
|
|
118
101
|
v-model="attrs.href"
|
|
119
102
|
density="compact"
|
|
@@ -122,9 +105,9 @@ watch(() => attrs.value.href, () => {
|
|
|
122
105
|
:error-messages="hrefInvalid ? t('dialog.link.href_error') : ''"
|
|
123
106
|
autofocus
|
|
124
107
|
/>
|
|
125
|
-
</
|
|
108
|
+
</div>
|
|
126
109
|
|
|
127
|
-
<
|
|
110
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--4">
|
|
128
111
|
<VSelect
|
|
129
112
|
v-model="attrs.target"
|
|
130
113
|
:items="targetAttrs"
|
|
@@ -133,13 +116,13 @@ watch(() => attrs.value.href, () => {
|
|
|
133
116
|
return-object
|
|
134
117
|
density="compact"
|
|
135
118
|
/>
|
|
136
|
-
</
|
|
119
|
+
</div>
|
|
137
120
|
|
|
138
|
-
<
|
|
121
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--8">
|
|
139
122
|
<VTextField v-model="attrs.cssClass" density="compact" variant="outlined" :label="t('dialog.link.class')" />
|
|
140
|
-
</
|
|
123
|
+
</div>
|
|
141
124
|
|
|
142
|
-
<
|
|
125
|
+
<div class="tiptapify-dialog-col">
|
|
143
126
|
<VSelect
|
|
144
127
|
v-model="attrs.rel"
|
|
145
128
|
:items="relAttrs"
|
|
@@ -151,28 +134,28 @@ watch(() => attrs.value.href, () => {
|
|
|
151
134
|
clearable
|
|
152
135
|
density="compact"
|
|
153
136
|
/>
|
|
154
|
-
</
|
|
155
|
-
</
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
156
139
|
</VCardText>
|
|
157
140
|
</template>
|
|
158
141
|
|
|
159
142
|
<template #actions>
|
|
160
143
|
<VCardActions>
|
|
161
|
-
<
|
|
162
|
-
<
|
|
144
|
+
<div class="tiptapify-dialog-actions">
|
|
145
|
+
<div class="tiptapify-dialog-actions__start">
|
|
163
146
|
<VBtn v-if="editor.isActive('link')" color="warning" :variant="variantBtn" :disabled="isDisabled" @click="clear">
|
|
164
147
|
{{ t('dialog.clear') }}
|
|
165
148
|
</VBtn>
|
|
166
|
-
</
|
|
167
|
-
<
|
|
168
|
-
<VBtn :variant="variantBtn"
|
|
149
|
+
</div>
|
|
150
|
+
<div class="tiptapify-dialog-actions__end">
|
|
151
|
+
<VBtn :variant="variantBtn" @click="close">
|
|
169
152
|
{{ t('dialog.close') }}
|
|
170
153
|
</VBtn>
|
|
171
154
|
<VBtn color="primary" :variant="variantBtn" :disabled="isDisabled || hrefInvalid" @click="apply">
|
|
172
155
|
{{ t('dialog.apply') }}
|
|
173
156
|
</VBtn>
|
|
174
|
-
</
|
|
175
|
-
</
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
176
159
|
</VCardActions>
|
|
177
160
|
</template>
|
|
178
161
|
</TiptapifyDialog>
|
|
@@ -98,16 +98,16 @@ onUnmounted(() => {
|
|
|
98
98
|
<TiptapifyDialog ref="dialog" module="video" :max-width="800">
|
|
99
99
|
<template #content>
|
|
100
100
|
<VCardText>
|
|
101
|
-
<
|
|
102
|
-
<!-- <
|
|
101
|
+
<div class="tiptapify-dialog-grid">
|
|
102
|
+
<!-- <div class="tiptapify-dialog-col">-->
|
|
103
103
|
<!-- <VSelect v-model="attrs.type" density="compact" variant="outlined" :label="t('dialog.video.src')" />-->
|
|
104
|
-
<!-- </
|
|
104
|
+
<!-- </div>-->
|
|
105
105
|
|
|
106
|
-
<
|
|
106
|
+
<div class="tiptapify-dialog-col">
|
|
107
107
|
<VTextField v-model="attrs.src" density="compact" variant="outlined" :label="t('dialog.video.src')" />
|
|
108
|
-
</
|
|
108
|
+
</div>
|
|
109
109
|
|
|
110
|
-
<
|
|
110
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--3">
|
|
111
111
|
<VTextField
|
|
112
112
|
v-model="attrs.width"
|
|
113
113
|
type="number"
|
|
@@ -117,9 +117,9 @@ onUnmounted(() => {
|
|
|
117
117
|
:min="1"
|
|
118
118
|
:label="t('dialog.video.width')"
|
|
119
119
|
/>
|
|
120
|
-
</
|
|
120
|
+
</div>
|
|
121
121
|
|
|
122
|
-
<
|
|
122
|
+
<div class="tiptapify-dialog-col tiptapify-dialog-col--3">
|
|
123
123
|
<VTextField
|
|
124
124
|
v-model="attrs.height"
|
|
125
125
|
type="number"
|
|
@@ -129,28 +129,28 @@ onUnmounted(() => {
|
|
|
129
129
|
:min="1"
|
|
130
130
|
:label="t('dialog.video.height')"
|
|
131
131
|
/>
|
|
132
|
-
</
|
|
133
|
-
</
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
134
|
</VCardText>
|
|
135
135
|
</template>
|
|
136
136
|
|
|
137
137
|
<template #actions>
|
|
138
138
|
<VCardActions>
|
|
139
|
-
<
|
|
140
|
-
<
|
|
139
|
+
<div class="tiptapify-dialog-actions">
|
|
140
|
+
<div class="tiptapify-dialog-actions__start">
|
|
141
141
|
<VBtn v-if="editor.isActive('image')" color="warning" :variant="variantBtn" :disabled="isDisabled" @click="clear">
|
|
142
142
|
{{ t('dialog.clear') }}
|
|
143
143
|
</VBtn>
|
|
144
|
-
</
|
|
145
|
-
<
|
|
146
|
-
<VBtn :variant="variantBtn"
|
|
144
|
+
</div>
|
|
145
|
+
<div class="tiptapify-dialog-actions__end">
|
|
146
|
+
<VBtn :variant="variantBtn" @click="close">
|
|
147
147
|
{{ t('dialog.close') }}
|
|
148
148
|
</VBtn>
|
|
149
149
|
<VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
|
|
150
150
|
{{ t('dialog.apply') }}
|
|
151
151
|
</VBtn>
|
|
152
|
-
</
|
|
153
|
-
</
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
154
|
</VCardActions>
|
|
155
155
|
</template>
|
|
156
156
|
</TiptapifyDialog>
|