tiptapify 0.2.4 → 0.2.5
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 +84644 -65141
- package/dist/tiptapify.umd.js +86 -84
- package/index.d.ts +23 -2
- package/package.json +45 -45
- package/src/components/Tiptapify.vue +83 -1
- 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 +337 -27
- 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 +3 -0
- package/src/types/editor.ts +23 -2
- package/src/utils/validateHref.test.ts +68 -0
- package/src/utils/validateHref.ts +21 -0
package/src/i18n/locales/vi.json
CHANGED
|
@@ -1,206 +1,212 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
"
|
|
5
|
-
},
|
|
6
|
-
"style": {
|
|
7
|
-
"paragraph": "Đoạn văn",
|
|
8
|
-
"heading": "Tiêu đề",
|
|
9
|
-
"headings": {
|
|
10
|
-
"h1": "Tiêu đề cấp 1",
|
|
11
|
-
"h2": "Tiêu đề cấp 2",
|
|
12
|
-
"h3": "Tiêu đề cấp 3",
|
|
13
|
-
"h4": "Tiêu đề cấp 4",
|
|
14
|
-
"h5": "Tiêu đề cấp 5",
|
|
15
|
-
"h6": "Tiêu đề cấp 6"
|
|
16
|
-
},
|
|
17
|
-
"fontFamily": "Gia phông chữ",
|
|
18
|
-
"fontSize": "Kích cỡ chữ",
|
|
19
|
-
"lineHeight": "Khoảng cách dòng",
|
|
20
|
-
"color": {
|
|
21
|
-
"highlight": "Màu tô đậm",
|
|
22
|
-
"text": "Màu văn bản",
|
|
23
|
-
"unset": "Xóa màu",
|
|
24
|
-
"custom": "Tùy chọn tùy chỉnh"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"format": {
|
|
28
|
-
"bold": "In đậm",
|
|
29
|
-
"italic": "In nghiêng",
|
|
30
|
-
"strike": "Gạch ngang",
|
|
31
|
-
"underline": "Gạch chân",
|
|
32
|
-
"sup": "Chữ viết trên",
|
|
33
|
-
"sub": "Chữ viết dưới",
|
|
34
|
-
"break": "Xuống dòng",
|
|
35
|
-
"line": "Đường thẳng ngang",
|
|
36
|
-
"blockquote": "Trích dẫn",
|
|
37
|
-
"code": "Mã",
|
|
38
|
-
"codeblock": "Khối mã",
|
|
39
|
-
"formatClear": "Xóa định dạng"
|
|
2
|
+
"action": {
|
|
3
|
+
"redo": "Làm lại",
|
|
4
|
+
"undo": "Hoàn tác"
|
|
40
5
|
},
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
6
|
+
"ai": {
|
|
7
|
+
"append": "Thêm vào cuối",
|
|
8
|
+
"defaultExamples": {
|
|
9
|
+
"expand": {
|
|
10
|
+
"prompt": "Mở rộng đoạn văn này thành phiên bản chi tiết hơn.",
|
|
11
|
+
"title": "Mở rộng"
|
|
12
|
+
},
|
|
13
|
+
"improve": {
|
|
14
|
+
"prompt": "Hãy cải thiện sự rõ ràng và giọng văn của đoạn văn này.",
|
|
15
|
+
"title": "Cải thiện bài viết"
|
|
16
|
+
},
|
|
17
|
+
"proofReading": {
|
|
18
|
+
"prompt": "Sửa ngữ pháp, chính tả và dấu câu mà không thay đổi ý nghĩa.",
|
|
19
|
+
"title": "Soạn thảo"
|
|
20
|
+
},
|
|
21
|
+
"summarize": {
|
|
22
|
+
"prompt": "Tóm tắt đoạn văn này thành một đoạn ngắn gọn.",
|
|
23
|
+
"title": "Tóm tắt"
|
|
59
24
|
}
|
|
60
25
|
},
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"deleteCol": "Xóa cột",
|
|
76
|
-
"mergeCells": "Hợp nhất ô",
|
|
77
|
-
"splitCell": "Tách ô"
|
|
78
|
-
},
|
|
79
|
-
"video": "Video",
|
|
80
|
-
"charmap": {
|
|
81
|
-
"title": "Chèn ký tự đặc biệt",
|
|
82
|
-
"search": "Tìm kiếm ký tự...",
|
|
83
|
-
"noResults": "Không tìm thấy ký tự phù hợp",
|
|
84
|
-
"categories": {
|
|
85
|
-
"punctuation": "Dấu câu",
|
|
86
|
-
"symbols": "Ký hiệu",
|
|
87
|
-
"math": "Toán học",
|
|
88
|
-
"currency": "Tiền tệ",
|
|
89
|
-
"greek": "Chữ cái Hy Lạp",
|
|
90
|
-
"extended_letters": "Chữ cái mở rộng",
|
|
91
|
-
"diacritics": "Dấu phụ",
|
|
92
|
-
"typography": "In ấn",
|
|
93
|
-
"cyrillic": "Chữ Kirin",
|
|
94
|
-
"hebrew": "Tiếng Do Thái",
|
|
95
|
-
"arrows": "Mũi tên",
|
|
96
|
-
"box_drawing": "Vẽ khung"
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
"action": {
|
|
101
|
-
"undo": "Hoàn tác",
|
|
102
|
-
"redo": "Làm lại"
|
|
26
|
+
"error": "Tạo nội dung AI thất bại",
|
|
27
|
+
"generate": "Tạo",
|
|
28
|
+
"insert": "Chèn",
|
|
29
|
+
"limit_exceeded": "Kết quả vượt quá giới hạn ký tự của trình soạn thảo. Hãy rút ngắn văn bản và áp dụng lại.",
|
|
30
|
+
"loading": "Đang tạo...",
|
|
31
|
+
"prompt": "Lệnh",
|
|
32
|
+
"quick_prompts": "Lệnh nhanh",
|
|
33
|
+
"reasoning_effort": "Mức độ suy luận",
|
|
34
|
+
"replace": "Thay thế",
|
|
35
|
+
"result": "Kết quả",
|
|
36
|
+
"stop": "Dừng",
|
|
37
|
+
"thinking": "Tư duy",
|
|
38
|
+
"title": "Viết bằng AI",
|
|
39
|
+
"unavailable": "Hãy cấu hình nhà cung cấp AI để sử dụng thao tác này"
|
|
103
40
|
},
|
|
104
41
|
"alignment": "Căn chỉnh",
|
|
105
42
|
"alignments": {
|
|
106
|
-
"left": "Canh trái",
|
|
107
43
|
"center": "Canh giữa",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
44
|
+
"justify": "Canh đều",
|
|
45
|
+
"left": "Canh trái",
|
|
46
|
+
"right": "Canh phải"
|
|
110
47
|
},
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
"bullet": "Danh sách không đánh số",
|
|
114
|
-
"numbered": "Danh sách có đánh số",
|
|
115
|
-
"task": "Danh sách công việc",
|
|
116
|
-
"indent": "Tăng thụt đầu dòng",
|
|
117
|
-
"outdent": "Giảm thụt đầu dòng"
|
|
48
|
+
"content": {
|
|
49
|
+
"placeholder": "Viết điều gì đó..."
|
|
118
50
|
},
|
|
51
|
+
"defaultValue": "Giá trị mặc định",
|
|
119
52
|
"dialog": {
|
|
120
53
|
"apply": "Áp dụng",
|
|
121
54
|
"clear": "Xóa",
|
|
122
55
|
"close": "Đóng",
|
|
123
56
|
"iframe": {
|
|
124
57
|
"dialog_title": "Thêm/sửa khung nhúng",
|
|
125
|
-
"
|
|
58
|
+
"frameborder": "Viền khung",
|
|
59
|
+
"height": "Chiều cao",
|
|
126
60
|
"name": "Tên",
|
|
61
|
+
"src": "Nguồn",
|
|
62
|
+
"src_invalid": "URL đã nhập không hợp lệ",
|
|
127
63
|
"title": "Tiêu đề",
|
|
128
|
-
"width": "Chiều rộng"
|
|
129
|
-
"height": "Chiều cao",
|
|
130
|
-
"frameborder": "Viền khung",
|
|
131
|
-
"src_invalid": "URL đã nhập không hợp lệ"
|
|
64
|
+
"width": "Chiều rộng"
|
|
132
65
|
},
|
|
133
66
|
"image": {
|
|
134
|
-
"title": "Tiêu đề",
|
|
135
|
-
"src": "Nguồn",
|
|
136
|
-
"keep_ratio": "Giữ tỷ lệ khung hình",
|
|
137
67
|
"alt": "Văn bản thay thế",
|
|
138
|
-
"
|
|
68
|
+
"dialog_title": "Thêm/sửa hình ảnh",
|
|
139
69
|
"height": "Chiều cao",
|
|
140
|
-
"
|
|
70
|
+
"keep_ratio": "Giữ tỷ lệ khung hình",
|
|
71
|
+
"src": "Nguồn",
|
|
72
|
+
"title": "Tiêu đề",
|
|
73
|
+
"width": "Chiều rộng"
|
|
141
74
|
},
|
|
142
75
|
"link": {
|
|
143
|
-
"
|
|
76
|
+
"class": "Lớp CSS",
|
|
144
77
|
"href": "Địa chỉ liên kết",
|
|
145
78
|
"href_error": "Địa chỉ liên kết không hợp lệ",
|
|
79
|
+
"rel": "liên hệ",
|
|
146
80
|
"target": "Mở tại...",
|
|
147
81
|
"target_blank": "Cửa sổ mới",
|
|
148
82
|
"target_self": "Cửa sổ hiện tại",
|
|
149
|
-
"
|
|
150
|
-
"class": "Lớp CSS"
|
|
83
|
+
"title": "Thêm/sửa liên kết"
|
|
151
84
|
},
|
|
152
85
|
"preview": {
|
|
153
86
|
"title": "Xem trước"
|
|
154
87
|
},
|
|
155
88
|
"source": {
|
|
156
|
-
"
|
|
157
|
-
"
|
|
89
|
+
"prettify": "Làm đẹp",
|
|
90
|
+
"title": "Xem mã nguồn"
|
|
158
91
|
},
|
|
159
92
|
"video": {
|
|
160
|
-
"
|
|
93
|
+
"height": "Chiều cao",
|
|
161
94
|
"src": "Nguồn",
|
|
162
|
-
"
|
|
163
|
-
"
|
|
95
|
+
"title": "Thêm/sửa video",
|
|
96
|
+
"width": "Chiều rộng"
|
|
164
97
|
}
|
|
165
98
|
},
|
|
99
|
+
"footer": {
|
|
100
|
+
"chars": "ký tự",
|
|
101
|
+
"limit": "giới hạn ký tự",
|
|
102
|
+
"words": "từ ngữ"
|
|
103
|
+
},
|
|
104
|
+
"format": {
|
|
105
|
+
"blockquote": "Trích dẫn",
|
|
106
|
+
"bold": "In đậm",
|
|
107
|
+
"break": "Xuống dòng",
|
|
108
|
+
"code": "Mã",
|
|
109
|
+
"codeblock": "Khối mã",
|
|
110
|
+
"formatClear": "Xóa định dạng",
|
|
111
|
+
"italic": "In nghiêng",
|
|
112
|
+
"line": "Đường thẳng ngang",
|
|
113
|
+
"strike": "Gạch ngang",
|
|
114
|
+
"sub": "Chữ viết dưới",
|
|
115
|
+
"sup": "Chữ viết trên",
|
|
116
|
+
"underline": "Gạch chân"
|
|
117
|
+
},
|
|
118
|
+
"list": "Danh sách",
|
|
119
|
+
"lists": {
|
|
120
|
+
"bullet": "Danh sách không đánh số",
|
|
121
|
+
"indent": "Tăng thụt đầu dòng",
|
|
122
|
+
"numbered": "Danh sách có đánh số",
|
|
123
|
+
"outdent": "Giảm thụt đầu dòng",
|
|
124
|
+
"task": "Danh sách công việc"
|
|
125
|
+
},
|
|
126
|
+
"media": {
|
|
127
|
+
"charmap": {
|
|
128
|
+
"categories": {
|
|
129
|
+
"arrows": "Mũi tên",
|
|
130
|
+
"box_drawing": "Vẽ khung",
|
|
131
|
+
"currency": "Tiền tệ",
|
|
132
|
+
"cyrillic": "Chữ Kirin",
|
|
133
|
+
"diacritics": "Dấu phụ",
|
|
134
|
+
"extended_letters": "Chữ cái mở rộng",
|
|
135
|
+
"greek": "Chữ cái Hy Lạp",
|
|
136
|
+
"hebrew": "Tiếng Do Thái",
|
|
137
|
+
"math": "Toán học",
|
|
138
|
+
"punctuation": "Dấu câu",
|
|
139
|
+
"symbols": "Ký hiệu",
|
|
140
|
+
"typography": "In ấn"
|
|
141
|
+
},
|
|
142
|
+
"noResults": "Không tìm thấy ký tự phù hợp",
|
|
143
|
+
"search": "Tìm kiếm ký tự...",
|
|
144
|
+
"title": "Chèn ký tự đặc biệt"
|
|
145
|
+
},
|
|
146
|
+
"emoji": {
|
|
147
|
+
"categories": {
|
|
148
|
+
"activities": "Hoạt động",
|
|
149
|
+
"animals_and_nature": "Động vật và thiên nhiên",
|
|
150
|
+
"component": "Thành phần",
|
|
151
|
+
"flags": "Cờ",
|
|
152
|
+
"food_and_drink": "Đồ ăn thức uống",
|
|
153
|
+
"objects": "Vật thể",
|
|
154
|
+
"people_and_body": "Con người và cơ thể",
|
|
155
|
+
"smileys_and_emotion": "Biểu tượng cảm xúc",
|
|
156
|
+
"symbols": "Ký hiệu",
|
|
157
|
+
"travel_and_places": "Du lịch và địa điểm"
|
|
158
|
+
},
|
|
159
|
+
"search": "Tìm kiếm biểu tượng cảm xúc...",
|
|
160
|
+
"title": "Biểu tượng cảm xúc"
|
|
161
|
+
},
|
|
162
|
+
"iframe": "khung nhúng",
|
|
163
|
+
"image": "Hình ảnh",
|
|
164
|
+
"link": "Liên kết ngoài",
|
|
165
|
+
"tables": {
|
|
166
|
+
"col": "Cột",
|
|
167
|
+
"cols": "Cột",
|
|
168
|
+
"deleteCol": "Xóa cột",
|
|
169
|
+
"deleteRow": "Xóa hàng",
|
|
170
|
+
"deleteTable": "Xóa bảng",
|
|
171
|
+
"insertColAfter": "Chèn cột sau",
|
|
172
|
+
"insertColBefore": "Chèn cột trước",
|
|
173
|
+
"insertRowAfter": "Chèn hàng sau",
|
|
174
|
+
"insertRowBefore": "Chèn hàng trước",
|
|
175
|
+
"insertTable": "Chèn bảng",
|
|
176
|
+
"insertWithHeaderRow": "Chèn bảng có dòng tiêu đề",
|
|
177
|
+
"mergeCells": "Hợp nhất ô",
|
|
178
|
+
"row": "Hàng",
|
|
179
|
+
"rows": "Hàng",
|
|
180
|
+
"splitCell": "Tách ô",
|
|
181
|
+
"table": "Bảng"
|
|
182
|
+
},
|
|
183
|
+
"video": "Video"
|
|
184
|
+
},
|
|
166
185
|
"misc": {
|
|
167
186
|
"fullscreen": "Chế độ toàn màn hình",
|
|
168
187
|
"preview": "Xem trước",
|
|
169
188
|
"source": "Xem mã nguồn",
|
|
170
189
|
"toggleInvisibleCharacters": "Hiện/ẩn ký tự vô hình"
|
|
171
190
|
},
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
"
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"proofReading": {
|
|
193
|
-
"title": "Proof-reading",
|
|
194
|
-
"prompt": "Correct grammar, spelling, and punctuation without changing the meaning."
|
|
195
|
-
},
|
|
196
|
-
"summarize": {
|
|
197
|
-
"title": "Summarize",
|
|
198
|
-
"prompt": "Summarize this text in a concise paragraph."
|
|
199
|
-
},
|
|
200
|
-
"expand": {
|
|
201
|
-
"title": "Expand",
|
|
202
|
-
"prompt": "Expand this into a more detailed version."
|
|
203
|
-
}
|
|
204
|
-
}
|
|
191
|
+
"style": {
|
|
192
|
+
"color": {
|
|
193
|
+
"custom": "Tùy chọn tùy chỉnh",
|
|
194
|
+
"highlight": "Màu tô đậm",
|
|
195
|
+
"text": "Màu văn bản",
|
|
196
|
+
"unset": "Xóa màu"
|
|
197
|
+
},
|
|
198
|
+
"fontFamily": "Gia phông chữ",
|
|
199
|
+
"fontSize": "Kích cỡ chữ",
|
|
200
|
+
"heading": "Tiêu đề",
|
|
201
|
+
"headings": {
|
|
202
|
+
"h1": "Tiêu đề cấp 1",
|
|
203
|
+
"h2": "Tiêu đề cấp 2",
|
|
204
|
+
"h3": "Tiêu đề cấp 3",
|
|
205
|
+
"h4": "Tiêu đề cấp 4",
|
|
206
|
+
"h5": "Tiêu đề cấp 5",
|
|
207
|
+
"h6": "Tiêu đề cấp 6"
|
|
208
|
+
},
|
|
209
|
+
"lineHeight": "Khoảng cách dòng",
|
|
210
|
+
"paragraph": "Đoạn văn"
|
|
205
211
|
}
|
|
206
212
|
}
|
package/src/index.ts
CHANGED
|
@@ -54,9 +54,12 @@ export type {
|
|
|
54
54
|
TiptapifyAiEditorContext,
|
|
55
55
|
TiptapifyAiOpenAiResponse,
|
|
56
56
|
TiptapifyAiPromptExample,
|
|
57
|
+
TiptapifyAiReasoningEffort,
|
|
58
|
+
TiptapifyAiReasoningEffortOptions,
|
|
57
59
|
TiptapifyAiProvider,
|
|
58
60
|
TiptapifyAiRequest,
|
|
59
61
|
TiptapifyAiResponse,
|
|
60
62
|
TiptapifyAiStorage,
|
|
63
|
+
TiptapifyAiStream,
|
|
61
64
|
TiptapifyAiTokenProvider,
|
|
62
65
|
} from '@tiptapify/types/editor'
|
package/src/types/editor.ts
CHANGED
|
@@ -38,10 +38,17 @@ export type TiptapifyAiRequest = {
|
|
|
38
38
|
model?: string,
|
|
39
39
|
messages: TiptapifyAiChatMessage[],
|
|
40
40
|
temperature?: number,
|
|
41
|
-
stream?:
|
|
41
|
+
stream?: boolean,
|
|
42
42
|
[key: string]: unknown,
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export type TiptapifyAiReasoningEffort = 'low' | 'medium' | 'high'
|
|
46
|
+
|
|
47
|
+
export type TiptapifyAiReasoningEffortOptions = {
|
|
48
|
+
options: TiptapifyAiReasoningEffort[],
|
|
49
|
+
default?: TiptapifyAiReasoningEffort,
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
export type TiptapifyAiResponse = {
|
|
46
53
|
content: string,
|
|
47
54
|
}
|
|
@@ -55,7 +62,17 @@ export type TiptapifyAiOpenAiResponse = {
|
|
|
55
62
|
}>,
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
export type
|
|
65
|
+
export type TiptapifyAiStream = {
|
|
66
|
+
signal: AbortSignal,
|
|
67
|
+
onChunk: (chunk: string) => void,
|
|
68
|
+
onReasoning: (chunk: string) => void,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type TiptapifyAiProvider = (
|
|
72
|
+
request: TiptapifyAiRequest,
|
|
73
|
+
context: TiptapifyAiEditorContext,
|
|
74
|
+
stream?: TiptapifyAiStream,
|
|
75
|
+
) => Promise<TiptapifyAiResponse | TiptapifyAiOpenAiResponse | string>
|
|
59
76
|
|
|
60
77
|
export type TiptapifyAiTokenProvider = () => Promise<string | null> | string | null
|
|
61
78
|
|
|
@@ -73,6 +90,10 @@ export type TiptapifyAiOptions = {
|
|
|
73
90
|
defaultPrompt?: string,
|
|
74
91
|
systemPrompt?: string,
|
|
75
92
|
temperature?: number,
|
|
93
|
+
stream?: boolean,
|
|
94
|
+
thinking?: boolean,
|
|
95
|
+
reasoningEffort?: TiptapifyAiReasoningEffortOptions,
|
|
96
|
+
showReasoning?: boolean,
|
|
76
97
|
chatCompletionOptions?: Record<string, unknown>,
|
|
77
98
|
createMessages?: (context: TiptapifyAiEditorContext) => TiptapifyAiChatMessage[],
|
|
78
99
|
tokenProvider?: TiptapifyAiTokenProvider,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { isValidHref } from './validateHref'
|
|
3
|
+
|
|
4
|
+
describe('isValidHref', () => {
|
|
5
|
+
it('accepts a URL with a path and query parameters', () => {
|
|
6
|
+
expect(isValidHref('https://google.com/search?q=123&page=12')).toBe(true)
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('accepts a URL with query parameters right after the domain slash', () => {
|
|
10
|
+
expect(isValidHref('https://google.com/?q=123&page=12')).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('accepts a URL with only a trailing slash', () => {
|
|
14
|
+
expect(isValidHref('https://google.com/')).toBe(true)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('accepts a URL with only a domain', () => {
|
|
18
|
+
expect(isValidHref('https://google.com')).toBe(true)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('accepts http URLs', () => {
|
|
22
|
+
expect(isValidHref('http://example.com')).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('accepts a URL with basic auth, nested path, fragment, query and extra parameters', () => {
|
|
26
|
+
expect(isValidHref('https://user:pass@example.com/a/b#frag?q=1&r=2')).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('accepts a query value with dashes, underscores and percent-encoded characters', () => {
|
|
30
|
+
expect(isValidHref('https://example.com/a/b?q=1-2_3%40&r=99')).toBe(true)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('accepts mailto links', () => {
|
|
34
|
+
expect(isValidHref('mailto:test@example.com')).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('accepts tel links', () => {
|
|
38
|
+
expect(isValidHref('tel:+79990001122')).toBe(true)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('rejects an empty string', () => {
|
|
42
|
+
expect(isValidHref('')).toBe(false)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('rejects a protocol-only URL', () => {
|
|
46
|
+
expect(isValidHref('https://')).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('rejects a domain without a TLD dot', () => {
|
|
50
|
+
expect(isValidHref('https://.com')).toBe(false)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('rejects unsupported protocols', () => {
|
|
54
|
+
expect(isValidHref('ftp://example.com')).toBe(false)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('rejects javascript pseudo-protocols', () => {
|
|
58
|
+
expect(isValidHref('javascript:alert(1)')).toBe(false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('rejects URLs containing spaces', () => {
|
|
62
|
+
expect(isValidHref('https://exa mple.com')).toBe(false)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('rejects plain text', () => {
|
|
66
|
+
expect(isValidHref('not a url')).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const azAZ09 = 'a-zA-Z0-9'
|
|
2
|
+
|
|
3
|
+
const regexHrefProto = 'https?:\\/\\/'
|
|
4
|
+
const regexHrefAuth = `([${azAZ09}]+(:[${azAZ09}]+)?@)?`
|
|
5
|
+
const regexHrefDomain = `[${azAZ09}]+(\\.[${azAZ09}]+(-?[${azAZ09}]+)?)+`
|
|
6
|
+
const regexHrefPath = `(\\/[${azAZ09}\\-]+)*\\/?`
|
|
7
|
+
const regexHrefFragment = '(#[^\\s]*)?'
|
|
8
|
+
const regexHrefQueryParam = `(\\?[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)?`
|
|
9
|
+
const regexHrefQueryParamExtra = `(&[${azAZ09}\\-_]+((\\[[${azAZ09}]+\\])?=[${azAZ09}\\-_%]+)?)*`
|
|
10
|
+
const regexHref = `${regexHrefProto}${regexHrefAuth}${regexHrefDomain}${regexHrefPath}${regexHrefFragment}${regexHrefQueryParam}${regexHrefQueryParamExtra}`
|
|
11
|
+
|
|
12
|
+
const regexMailto = `mailto:\\w+@[${azAZ09}]+(\\.[${azAZ09}]+)*`
|
|
13
|
+
const regexTel = 'tel:\\+?[0-9]+'
|
|
14
|
+
|
|
15
|
+
const regexAll = [regexHref, regexMailto, regexTel].join('|')
|
|
16
|
+
|
|
17
|
+
const hrefRegex = new RegExp(`^(${regexAll})$`, 'i')
|
|
18
|
+
|
|
19
|
+
export function isValidHref(href: string): boolean {
|
|
20
|
+
return hrefRegex.test(href || '')
|
|
21
|
+
}
|