@seorii/tiptap 0.4.1 → 0.4.2
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/dist/i18n/es/index.d.ts +51 -0
- package/dist/i18n/es/index.js +50 -0
- package/dist/i18n/index.d.ts +196 -0
- package/dist/i18n/index.js +19 -2
- package/dist/i18n/ja/index.d.ts +51 -0
- package/dist/i18n/ja/index.js +50 -0
- package/dist/i18n/zh-hans/index.d.ts +51 -0
- package/dist/i18n/zh-hans/index.js +50 -0
- package/dist/i18n/zh-hant/index.d.ts +51 -0
- package/dist/i18n/zh-hant/index.js +50 -0
- package/dist/plugin/resize/index.js +229 -38
- package/dist/tiptap/TipTap.svelte +101 -10
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
target: string[];
|
|
3
|
+
lang: string;
|
|
4
|
+
country: string;
|
|
5
|
+
text: string;
|
|
6
|
+
block: string;
|
|
7
|
+
loading: string;
|
|
8
|
+
delete: string;
|
|
9
|
+
close: string;
|
|
10
|
+
cancel: string;
|
|
11
|
+
insert: string;
|
|
12
|
+
noResult: string;
|
|
13
|
+
default: string;
|
|
14
|
+
auto: string;
|
|
15
|
+
title: string;
|
|
16
|
+
paragraph: string;
|
|
17
|
+
link: string;
|
|
18
|
+
alignLeft: string;
|
|
19
|
+
alignCenter: string;
|
|
20
|
+
alignRight: string;
|
|
21
|
+
alignJustify: string;
|
|
22
|
+
unorderedList: string;
|
|
23
|
+
numberList: string;
|
|
24
|
+
codeBlock: string;
|
|
25
|
+
mathBlock: string;
|
|
26
|
+
table: string;
|
|
27
|
+
twoColumns: string;
|
|
28
|
+
threeColumns: string;
|
|
29
|
+
image: string;
|
|
30
|
+
iframe: string;
|
|
31
|
+
youtube: string;
|
|
32
|
+
blockquote: string;
|
|
33
|
+
title1Info: string;
|
|
34
|
+
title2Info: string;
|
|
35
|
+
title3Info: string;
|
|
36
|
+
unorderedListInfo: string;
|
|
37
|
+
numberListInfo: string;
|
|
38
|
+
codeBlockInfo: string;
|
|
39
|
+
mathBlockInfo: string;
|
|
40
|
+
tableInfo: string;
|
|
41
|
+
twoColumnsInfo: string;
|
|
42
|
+
threeColumnsInfo: string;
|
|
43
|
+
imageInfo: string;
|
|
44
|
+
iframeInfo: string;
|
|
45
|
+
youtubeInfo: string;
|
|
46
|
+
blockquoteInfo: string;
|
|
47
|
+
newLineInfo: string;
|
|
48
|
+
placeholder: string;
|
|
49
|
+
insertCode: string;
|
|
50
|
+
};
|
|
51
|
+
export default _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
target: ['es', 'es-ES', 'es-419', 'es-MX'],
|
|
3
|
+
lang: 'es',
|
|
4
|
+
country: 'ES',
|
|
5
|
+
text: 'Texto',
|
|
6
|
+
block: 'Bloque',
|
|
7
|
+
loading: 'Cargando...',
|
|
8
|
+
delete: 'Eliminar',
|
|
9
|
+
close: 'Cerrar',
|
|
10
|
+
cancel: 'Cancelar',
|
|
11
|
+
insert: 'Insertar',
|
|
12
|
+
noResult: 'Sin resultados',
|
|
13
|
+
default: 'predeterminado',
|
|
14
|
+
auto: 'auto',
|
|
15
|
+
title: 'Título',
|
|
16
|
+
paragraph: 'Párrafo',
|
|
17
|
+
link: 'Enlace',
|
|
18
|
+
alignLeft: 'Alinear a la izquierda',
|
|
19
|
+
alignCenter: 'Centrar',
|
|
20
|
+
alignRight: 'Alinear a la derecha',
|
|
21
|
+
alignJustify: 'Justificar',
|
|
22
|
+
unorderedList: 'Lista con viñetas',
|
|
23
|
+
numberList: 'Lista numerada',
|
|
24
|
+
codeBlock: 'Bloque de código',
|
|
25
|
+
mathBlock: 'Bloque matemático',
|
|
26
|
+
table: 'Tabla',
|
|
27
|
+
twoColumns: '2 columnas',
|
|
28
|
+
threeColumns: '3 columnas',
|
|
29
|
+
image: 'Imagen',
|
|
30
|
+
iframe: 'iframe',
|
|
31
|
+
youtube: 'YouTube',
|
|
32
|
+
blockquote: 'Cita',
|
|
33
|
+
title1Info: 'Título grande',
|
|
34
|
+
title2Info: 'Título más pequeño',
|
|
35
|
+
title3Info: 'Título mediano',
|
|
36
|
+
unorderedListInfo: 'Lista sin orden',
|
|
37
|
+
numberListInfo: '1, 2, 3, 4',
|
|
38
|
+
codeBlockInfo: 'Bloque de código con resaltado de sintaxis',
|
|
39
|
+
mathBlockInfo: 'Bloque matemático',
|
|
40
|
+
tableInfo: 'Tabla',
|
|
41
|
+
twoColumnsInfo: 'Diseño de dos columnas',
|
|
42
|
+
threeColumnsInfo: 'Diseño de tres columnas',
|
|
43
|
+
imageInfo: 'Imagen',
|
|
44
|
+
iframeInfo: 'Insertar otro sitio web',
|
|
45
|
+
youtubeInfo: 'Insertar video de YouTube',
|
|
46
|
+
blockquoteInfo: 'Cita',
|
|
47
|
+
newLineInfo: 'Pulsa / para abrir comandos. O',
|
|
48
|
+
placeholder: 'Escribe contenido aquí...',
|
|
49
|
+
insertCode: 'Insertar código'
|
|
50
|
+
};
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -96,6 +96,202 @@ declare const locales: readonly [{
|
|
|
96
96
|
newLineInfo: string;
|
|
97
97
|
placeholder: string;
|
|
98
98
|
insertCode: string;
|
|
99
|
+
}, {
|
|
100
|
+
target: string[];
|
|
101
|
+
lang: string;
|
|
102
|
+
country: string;
|
|
103
|
+
text: string;
|
|
104
|
+
block: string;
|
|
105
|
+
loading: string;
|
|
106
|
+
delete: string;
|
|
107
|
+
close: string;
|
|
108
|
+
cancel: string;
|
|
109
|
+
insert: string;
|
|
110
|
+
noResult: string;
|
|
111
|
+
default: string;
|
|
112
|
+
auto: string;
|
|
113
|
+
title: string;
|
|
114
|
+
paragraph: string;
|
|
115
|
+
link: string;
|
|
116
|
+
alignLeft: string;
|
|
117
|
+
alignCenter: string;
|
|
118
|
+
alignRight: string;
|
|
119
|
+
alignJustify: string;
|
|
120
|
+
unorderedList: string;
|
|
121
|
+
numberList: string;
|
|
122
|
+
codeBlock: string;
|
|
123
|
+
mathBlock: string;
|
|
124
|
+
table: string;
|
|
125
|
+
twoColumns: string;
|
|
126
|
+
threeColumns: string;
|
|
127
|
+
image: string;
|
|
128
|
+
iframe: string;
|
|
129
|
+
youtube: string;
|
|
130
|
+
blockquote: string;
|
|
131
|
+
title1Info: string;
|
|
132
|
+
title2Info: string;
|
|
133
|
+
title3Info: string;
|
|
134
|
+
unorderedListInfo: string;
|
|
135
|
+
numberListInfo: string;
|
|
136
|
+
codeBlockInfo: string;
|
|
137
|
+
mathBlockInfo: string;
|
|
138
|
+
tableInfo: string;
|
|
139
|
+
twoColumnsInfo: string;
|
|
140
|
+
threeColumnsInfo: string;
|
|
141
|
+
imageInfo: string;
|
|
142
|
+
iframeInfo: string;
|
|
143
|
+
youtubeInfo: string;
|
|
144
|
+
blockquoteInfo: string;
|
|
145
|
+
newLineInfo: string;
|
|
146
|
+
placeholder: string;
|
|
147
|
+
insertCode: string;
|
|
148
|
+
}, {
|
|
149
|
+
target: string[];
|
|
150
|
+
lang: string;
|
|
151
|
+
country: string;
|
|
152
|
+
text: string;
|
|
153
|
+
block: string;
|
|
154
|
+
loading: string;
|
|
155
|
+
delete: string;
|
|
156
|
+
close: string;
|
|
157
|
+
cancel: string;
|
|
158
|
+
insert: string;
|
|
159
|
+
noResult: string;
|
|
160
|
+
default: string;
|
|
161
|
+
auto: string;
|
|
162
|
+
title: string;
|
|
163
|
+
paragraph: string;
|
|
164
|
+
link: string;
|
|
165
|
+
alignLeft: string;
|
|
166
|
+
alignCenter: string;
|
|
167
|
+
alignRight: string;
|
|
168
|
+
alignJustify: string;
|
|
169
|
+
unorderedList: string;
|
|
170
|
+
numberList: string;
|
|
171
|
+
codeBlock: string;
|
|
172
|
+
mathBlock: string;
|
|
173
|
+
table: string;
|
|
174
|
+
twoColumns: string;
|
|
175
|
+
threeColumns: string;
|
|
176
|
+
image: string;
|
|
177
|
+
iframe: string;
|
|
178
|
+
youtube: string;
|
|
179
|
+
blockquote: string;
|
|
180
|
+
title1Info: string;
|
|
181
|
+
title2Info: string;
|
|
182
|
+
title3Info: string;
|
|
183
|
+
unorderedListInfo: string;
|
|
184
|
+
numberListInfo: string;
|
|
185
|
+
codeBlockInfo: string;
|
|
186
|
+
mathBlockInfo: string;
|
|
187
|
+
tableInfo: string;
|
|
188
|
+
twoColumnsInfo: string;
|
|
189
|
+
threeColumnsInfo: string;
|
|
190
|
+
imageInfo: string;
|
|
191
|
+
iframeInfo: string;
|
|
192
|
+
youtubeInfo: string;
|
|
193
|
+
blockquoteInfo: string;
|
|
194
|
+
newLineInfo: string;
|
|
195
|
+
placeholder: string;
|
|
196
|
+
insertCode: string;
|
|
197
|
+
}, {
|
|
198
|
+
target: string[];
|
|
199
|
+
lang: string;
|
|
200
|
+
country: string;
|
|
201
|
+
text: string;
|
|
202
|
+
block: string;
|
|
203
|
+
loading: string;
|
|
204
|
+
delete: string;
|
|
205
|
+
close: string;
|
|
206
|
+
cancel: string;
|
|
207
|
+
insert: string;
|
|
208
|
+
noResult: string;
|
|
209
|
+
default: string;
|
|
210
|
+
auto: string;
|
|
211
|
+
title: string;
|
|
212
|
+
paragraph: string;
|
|
213
|
+
link: string;
|
|
214
|
+
alignLeft: string;
|
|
215
|
+
alignCenter: string;
|
|
216
|
+
alignRight: string;
|
|
217
|
+
alignJustify: string;
|
|
218
|
+
unorderedList: string;
|
|
219
|
+
numberList: string;
|
|
220
|
+
codeBlock: string;
|
|
221
|
+
mathBlock: string;
|
|
222
|
+
table: string;
|
|
223
|
+
twoColumns: string;
|
|
224
|
+
threeColumns: string;
|
|
225
|
+
image: string;
|
|
226
|
+
iframe: string;
|
|
227
|
+
youtube: string;
|
|
228
|
+
blockquote: string;
|
|
229
|
+
title1Info: string;
|
|
230
|
+
title2Info: string;
|
|
231
|
+
title3Info: string;
|
|
232
|
+
unorderedListInfo: string;
|
|
233
|
+
numberListInfo: string;
|
|
234
|
+
codeBlockInfo: string;
|
|
235
|
+
mathBlockInfo: string;
|
|
236
|
+
tableInfo: string;
|
|
237
|
+
twoColumnsInfo: string;
|
|
238
|
+
threeColumnsInfo: string;
|
|
239
|
+
imageInfo: string;
|
|
240
|
+
iframeInfo: string;
|
|
241
|
+
youtubeInfo: string;
|
|
242
|
+
blockquoteInfo: string;
|
|
243
|
+
newLineInfo: string;
|
|
244
|
+
placeholder: string;
|
|
245
|
+
insertCode: string;
|
|
246
|
+
}, {
|
|
247
|
+
target: string[];
|
|
248
|
+
lang: string;
|
|
249
|
+
country: string;
|
|
250
|
+
text: string;
|
|
251
|
+
block: string;
|
|
252
|
+
loading: string;
|
|
253
|
+
delete: string;
|
|
254
|
+
close: string;
|
|
255
|
+
cancel: string;
|
|
256
|
+
insert: string;
|
|
257
|
+
noResult: string;
|
|
258
|
+
default: string;
|
|
259
|
+
auto: string;
|
|
260
|
+
title: string;
|
|
261
|
+
paragraph: string;
|
|
262
|
+
link: string;
|
|
263
|
+
alignLeft: string;
|
|
264
|
+
alignCenter: string;
|
|
265
|
+
alignRight: string;
|
|
266
|
+
alignJustify: string;
|
|
267
|
+
unorderedList: string;
|
|
268
|
+
numberList: string;
|
|
269
|
+
codeBlock: string;
|
|
270
|
+
mathBlock: string;
|
|
271
|
+
table: string;
|
|
272
|
+
twoColumns: string;
|
|
273
|
+
threeColumns: string;
|
|
274
|
+
image: string;
|
|
275
|
+
iframe: string;
|
|
276
|
+
youtube: string;
|
|
277
|
+
blockquote: string;
|
|
278
|
+
title1Info: string;
|
|
279
|
+
title2Info: string;
|
|
280
|
+
title3Info: string;
|
|
281
|
+
unorderedListInfo: string;
|
|
282
|
+
numberListInfo: string;
|
|
283
|
+
codeBlockInfo: string;
|
|
284
|
+
mathBlockInfo: string;
|
|
285
|
+
tableInfo: string;
|
|
286
|
+
twoColumnsInfo: string;
|
|
287
|
+
threeColumnsInfo: string;
|
|
288
|
+
imageInfo: string;
|
|
289
|
+
iframeInfo: string;
|
|
290
|
+
youtubeInfo: string;
|
|
291
|
+
blockquoteInfo: string;
|
|
292
|
+
newLineInfo: string;
|
|
293
|
+
placeholder: string;
|
|
294
|
+
insertCode: string;
|
|
99
295
|
}];
|
|
100
296
|
type Locale = (typeof locales)[number];
|
|
101
297
|
export type LocaleInput = string | Locale | null | undefined;
|
package/dist/i18n/index.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import enUs from './en-us/index';
|
|
2
2
|
import koKr from './ko-kr/index';
|
|
3
|
-
|
|
3
|
+
import es from './es/index';
|
|
4
|
+
import ja from './ja/index';
|
|
5
|
+
import zhHans from './zh-hans/index';
|
|
6
|
+
import zhHant from './zh-hant/index';
|
|
7
|
+
const locales = [enUs, koKr, es, ja, zhHans, zhHant];
|
|
4
8
|
export const I18N_CONTEXT = Symbol('tiptap-i18n');
|
|
5
|
-
const normalizeLocaleCode = (value) =>
|
|
9
|
+
const normalizeLocaleCode = (value) => {
|
|
10
|
+
const normalized = (value ?? '').trim().replace(/_/g, '-').toLowerCase();
|
|
11
|
+
if (!normalized)
|
|
12
|
+
return '';
|
|
13
|
+
if (!normalized.startsWith('zh'))
|
|
14
|
+
return normalized;
|
|
15
|
+
if (normalized.includes('hant') ||
|
|
16
|
+
normalized.startsWith('zh-tw') ||
|
|
17
|
+
normalized.startsWith('zh-hk') ||
|
|
18
|
+
normalized.startsWith('zh-mo')) {
|
|
19
|
+
return 'zh-hant';
|
|
20
|
+
}
|
|
21
|
+
return 'zh-hans';
|
|
22
|
+
};
|
|
6
23
|
const findLocale = (localeList, language) => {
|
|
7
24
|
const normalized = normalizeLocaleCode(language);
|
|
8
25
|
if (!normalized)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
target: string[];
|
|
3
|
+
lang: string;
|
|
4
|
+
country: string;
|
|
5
|
+
text: string;
|
|
6
|
+
block: string;
|
|
7
|
+
loading: string;
|
|
8
|
+
delete: string;
|
|
9
|
+
close: string;
|
|
10
|
+
cancel: string;
|
|
11
|
+
insert: string;
|
|
12
|
+
noResult: string;
|
|
13
|
+
default: string;
|
|
14
|
+
auto: string;
|
|
15
|
+
title: string;
|
|
16
|
+
paragraph: string;
|
|
17
|
+
link: string;
|
|
18
|
+
alignLeft: string;
|
|
19
|
+
alignCenter: string;
|
|
20
|
+
alignRight: string;
|
|
21
|
+
alignJustify: string;
|
|
22
|
+
unorderedList: string;
|
|
23
|
+
numberList: string;
|
|
24
|
+
codeBlock: string;
|
|
25
|
+
mathBlock: string;
|
|
26
|
+
table: string;
|
|
27
|
+
twoColumns: string;
|
|
28
|
+
threeColumns: string;
|
|
29
|
+
image: string;
|
|
30
|
+
iframe: string;
|
|
31
|
+
youtube: string;
|
|
32
|
+
blockquote: string;
|
|
33
|
+
title1Info: string;
|
|
34
|
+
title2Info: string;
|
|
35
|
+
title3Info: string;
|
|
36
|
+
unorderedListInfo: string;
|
|
37
|
+
numberListInfo: string;
|
|
38
|
+
codeBlockInfo: string;
|
|
39
|
+
mathBlockInfo: string;
|
|
40
|
+
tableInfo: string;
|
|
41
|
+
twoColumnsInfo: string;
|
|
42
|
+
threeColumnsInfo: string;
|
|
43
|
+
imageInfo: string;
|
|
44
|
+
iframeInfo: string;
|
|
45
|
+
youtubeInfo: string;
|
|
46
|
+
blockquoteInfo: string;
|
|
47
|
+
newLineInfo: string;
|
|
48
|
+
placeholder: string;
|
|
49
|
+
insertCode: string;
|
|
50
|
+
};
|
|
51
|
+
export default _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
target: ['ja', 'ja-JP'],
|
|
3
|
+
lang: 'ja',
|
|
4
|
+
country: 'JP',
|
|
5
|
+
text: 'テキスト',
|
|
6
|
+
block: 'ブロック',
|
|
7
|
+
loading: '読み込み中...',
|
|
8
|
+
delete: '削除',
|
|
9
|
+
close: '閉じる',
|
|
10
|
+
cancel: 'キャンセル',
|
|
11
|
+
insert: '挿入',
|
|
12
|
+
noResult: '結果なし',
|
|
13
|
+
default: 'デフォルト',
|
|
14
|
+
auto: '自動',
|
|
15
|
+
title: '見出し',
|
|
16
|
+
paragraph: '本文',
|
|
17
|
+
link: 'リンク',
|
|
18
|
+
alignLeft: '左揃え',
|
|
19
|
+
alignCenter: '中央揃え',
|
|
20
|
+
alignRight: '右揃え',
|
|
21
|
+
alignJustify: '両端揃え',
|
|
22
|
+
unorderedList: '箇条書き',
|
|
23
|
+
numberList: '番号付きリスト',
|
|
24
|
+
codeBlock: 'コードブロック',
|
|
25
|
+
mathBlock: '数式ブロック',
|
|
26
|
+
table: '表',
|
|
27
|
+
twoColumns: '2カラム',
|
|
28
|
+
threeColumns: '3カラム',
|
|
29
|
+
image: '画像',
|
|
30
|
+
iframe: 'iframe',
|
|
31
|
+
youtube: 'YouTube',
|
|
32
|
+
blockquote: '引用',
|
|
33
|
+
title1Info: '大きな見出し',
|
|
34
|
+
title2Info: 'やや小さい見出し',
|
|
35
|
+
title3Info: '中くらいの見出し',
|
|
36
|
+
unorderedListInfo: '順序なしリスト',
|
|
37
|
+
numberListInfo: '1, 2, 3, 4',
|
|
38
|
+
codeBlockInfo: 'シンタックスハイライト付きコードブロック',
|
|
39
|
+
mathBlockInfo: '数式ブロック',
|
|
40
|
+
tableInfo: '表',
|
|
41
|
+
twoColumnsInfo: '2カラムレイアウト',
|
|
42
|
+
threeColumnsInfo: '3カラムレイアウト',
|
|
43
|
+
imageInfo: '画像',
|
|
44
|
+
iframeInfo: '別のウェブサイトを埋め込む',
|
|
45
|
+
youtubeInfo: 'YouTube動画を埋め込む',
|
|
46
|
+
blockquoteInfo: '引用ブロック',
|
|
47
|
+
newLineInfo: '/ でコマンドを開く。または',
|
|
48
|
+
placeholder: 'ここに内容を入力...',
|
|
49
|
+
insertCode: 'コードを挿入'
|
|
50
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
target: string[];
|
|
3
|
+
lang: string;
|
|
4
|
+
country: string;
|
|
5
|
+
text: string;
|
|
6
|
+
block: string;
|
|
7
|
+
loading: string;
|
|
8
|
+
delete: string;
|
|
9
|
+
close: string;
|
|
10
|
+
cancel: string;
|
|
11
|
+
insert: string;
|
|
12
|
+
noResult: string;
|
|
13
|
+
default: string;
|
|
14
|
+
auto: string;
|
|
15
|
+
title: string;
|
|
16
|
+
paragraph: string;
|
|
17
|
+
link: string;
|
|
18
|
+
alignLeft: string;
|
|
19
|
+
alignCenter: string;
|
|
20
|
+
alignRight: string;
|
|
21
|
+
alignJustify: string;
|
|
22
|
+
unorderedList: string;
|
|
23
|
+
numberList: string;
|
|
24
|
+
codeBlock: string;
|
|
25
|
+
mathBlock: string;
|
|
26
|
+
table: string;
|
|
27
|
+
twoColumns: string;
|
|
28
|
+
threeColumns: string;
|
|
29
|
+
image: string;
|
|
30
|
+
iframe: string;
|
|
31
|
+
youtube: string;
|
|
32
|
+
blockquote: string;
|
|
33
|
+
title1Info: string;
|
|
34
|
+
title2Info: string;
|
|
35
|
+
title3Info: string;
|
|
36
|
+
unorderedListInfo: string;
|
|
37
|
+
numberListInfo: string;
|
|
38
|
+
codeBlockInfo: string;
|
|
39
|
+
mathBlockInfo: string;
|
|
40
|
+
tableInfo: string;
|
|
41
|
+
twoColumnsInfo: string;
|
|
42
|
+
threeColumnsInfo: string;
|
|
43
|
+
imageInfo: string;
|
|
44
|
+
iframeInfo: string;
|
|
45
|
+
youtubeInfo: string;
|
|
46
|
+
blockquoteInfo: string;
|
|
47
|
+
newLineInfo: string;
|
|
48
|
+
placeholder: string;
|
|
49
|
+
insertCode: string;
|
|
50
|
+
};
|
|
51
|
+
export default _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
target: ['zh', 'zh-CN', 'zh-SG', 'zh-Hans'],
|
|
3
|
+
lang: 'zh',
|
|
4
|
+
country: 'CN',
|
|
5
|
+
text: '文本',
|
|
6
|
+
block: '区块',
|
|
7
|
+
loading: '加载中...',
|
|
8
|
+
delete: '删除',
|
|
9
|
+
close: '关闭',
|
|
10
|
+
cancel: '取消',
|
|
11
|
+
insert: '插入',
|
|
12
|
+
noResult: '无结果',
|
|
13
|
+
default: '默认',
|
|
14
|
+
auto: '自动',
|
|
15
|
+
title: '标题',
|
|
16
|
+
paragraph: '正文',
|
|
17
|
+
link: '链接',
|
|
18
|
+
alignLeft: '左对齐',
|
|
19
|
+
alignCenter: '居中对齐',
|
|
20
|
+
alignRight: '右对齐',
|
|
21
|
+
alignJustify: '两端对齐',
|
|
22
|
+
unorderedList: '无序列表',
|
|
23
|
+
numberList: '有序列表',
|
|
24
|
+
codeBlock: '代码块',
|
|
25
|
+
mathBlock: '公式块',
|
|
26
|
+
table: '表格',
|
|
27
|
+
twoColumns: '2 列',
|
|
28
|
+
threeColumns: '3 列',
|
|
29
|
+
image: '图片',
|
|
30
|
+
iframe: 'iframe',
|
|
31
|
+
youtube: 'YouTube',
|
|
32
|
+
blockquote: '引用',
|
|
33
|
+
title1Info: '大标题',
|
|
34
|
+
title2Info: '较小标题',
|
|
35
|
+
title3Info: '中等标题',
|
|
36
|
+
unorderedListInfo: '无序列表',
|
|
37
|
+
numberListInfo: '1, 2, 3, 4',
|
|
38
|
+
codeBlockInfo: '带语法高亮的代码块',
|
|
39
|
+
mathBlockInfo: '公式块',
|
|
40
|
+
tableInfo: '插入表格',
|
|
41
|
+
twoColumnsInfo: '两列布局',
|
|
42
|
+
threeColumnsInfo: '三列布局',
|
|
43
|
+
imageInfo: '图片',
|
|
44
|
+
iframeInfo: '嵌入其他网站',
|
|
45
|
+
youtubeInfo: '嵌入 YouTube 视频',
|
|
46
|
+
blockquoteInfo: '引用块',
|
|
47
|
+
newLineInfo: '按 / 输入命令,或',
|
|
48
|
+
placeholder: '在此输入内容...',
|
|
49
|
+
insertCode: '插入代码'
|
|
50
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
target: string[];
|
|
3
|
+
lang: string;
|
|
4
|
+
country: string;
|
|
5
|
+
text: string;
|
|
6
|
+
block: string;
|
|
7
|
+
loading: string;
|
|
8
|
+
delete: string;
|
|
9
|
+
close: string;
|
|
10
|
+
cancel: string;
|
|
11
|
+
insert: string;
|
|
12
|
+
noResult: string;
|
|
13
|
+
default: string;
|
|
14
|
+
auto: string;
|
|
15
|
+
title: string;
|
|
16
|
+
paragraph: string;
|
|
17
|
+
link: string;
|
|
18
|
+
alignLeft: string;
|
|
19
|
+
alignCenter: string;
|
|
20
|
+
alignRight: string;
|
|
21
|
+
alignJustify: string;
|
|
22
|
+
unorderedList: string;
|
|
23
|
+
numberList: string;
|
|
24
|
+
codeBlock: string;
|
|
25
|
+
mathBlock: string;
|
|
26
|
+
table: string;
|
|
27
|
+
twoColumns: string;
|
|
28
|
+
threeColumns: string;
|
|
29
|
+
image: string;
|
|
30
|
+
iframe: string;
|
|
31
|
+
youtube: string;
|
|
32
|
+
blockquote: string;
|
|
33
|
+
title1Info: string;
|
|
34
|
+
title2Info: string;
|
|
35
|
+
title3Info: string;
|
|
36
|
+
unorderedListInfo: string;
|
|
37
|
+
numberListInfo: string;
|
|
38
|
+
codeBlockInfo: string;
|
|
39
|
+
mathBlockInfo: string;
|
|
40
|
+
tableInfo: string;
|
|
41
|
+
twoColumnsInfo: string;
|
|
42
|
+
threeColumnsInfo: string;
|
|
43
|
+
imageInfo: string;
|
|
44
|
+
iframeInfo: string;
|
|
45
|
+
youtubeInfo: string;
|
|
46
|
+
blockquoteInfo: string;
|
|
47
|
+
newLineInfo: string;
|
|
48
|
+
placeholder: string;
|
|
49
|
+
insertCode: string;
|
|
50
|
+
};
|
|
51
|
+
export default _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
target: ['zh-TW', 'zh-HK', 'zh-MO', 'zh-Hant'],
|
|
3
|
+
lang: 'zh',
|
|
4
|
+
country: 'TW',
|
|
5
|
+
text: '文字',
|
|
6
|
+
block: '區塊',
|
|
7
|
+
loading: '載入中...',
|
|
8
|
+
delete: '刪除',
|
|
9
|
+
close: '關閉',
|
|
10
|
+
cancel: '取消',
|
|
11
|
+
insert: '插入',
|
|
12
|
+
noResult: '無結果',
|
|
13
|
+
default: '預設',
|
|
14
|
+
auto: '自動',
|
|
15
|
+
title: '標題',
|
|
16
|
+
paragraph: '段落',
|
|
17
|
+
link: '連結',
|
|
18
|
+
alignLeft: '靠左對齊',
|
|
19
|
+
alignCenter: '置中對齊',
|
|
20
|
+
alignRight: '靠右對齊',
|
|
21
|
+
alignJustify: '左右對齊',
|
|
22
|
+
unorderedList: '項目清單',
|
|
23
|
+
numberList: '編號清單',
|
|
24
|
+
codeBlock: '程式碼區塊',
|
|
25
|
+
mathBlock: '數學區塊',
|
|
26
|
+
table: '表格',
|
|
27
|
+
twoColumns: '2 欄',
|
|
28
|
+
threeColumns: '3 欄',
|
|
29
|
+
image: '圖片',
|
|
30
|
+
iframe: 'iframe',
|
|
31
|
+
youtube: 'YouTube',
|
|
32
|
+
blockquote: '引用',
|
|
33
|
+
title1Info: '大標題',
|
|
34
|
+
title2Info: '較小標題',
|
|
35
|
+
title3Info: '中等標題',
|
|
36
|
+
unorderedListInfo: '無序清單',
|
|
37
|
+
numberListInfo: '1, 2, 3, 4',
|
|
38
|
+
codeBlockInfo: '含語法高亮的程式碼區塊',
|
|
39
|
+
mathBlockInfo: '數學區塊',
|
|
40
|
+
tableInfo: '插入表格',
|
|
41
|
+
twoColumnsInfo: '雙欄版面',
|
|
42
|
+
threeColumnsInfo: '三欄版面',
|
|
43
|
+
imageInfo: '圖片',
|
|
44
|
+
iframeInfo: '嵌入其他網站',
|
|
45
|
+
youtubeInfo: '嵌入 YouTube 影片',
|
|
46
|
+
blockquoteInfo: '引用區塊',
|
|
47
|
+
newLineInfo: '按 / 輸入指令,或',
|
|
48
|
+
placeholder: '在此輸入內容...',
|
|
49
|
+
insertCode: '插入程式碼'
|
|
50
|
+
};
|
|
@@ -19,6 +19,15 @@ const minHeight = {
|
|
|
19
19
|
attr: 160
|
|
20
20
|
};
|
|
21
21
|
const maxHeight = 1600;
|
|
22
|
+
const aspectRatioOptions = [
|
|
23
|
+
{ label: 'Auto', value: null },
|
|
24
|
+
{ label: '16:9', value: '16:9' },
|
|
25
|
+
{ label: '3:2', value: '3:2' },
|
|
26
|
+
{ label: '21:9', value: '21:9' },
|
|
27
|
+
{ label: '1:1', value: '1:1' },
|
|
28
|
+
{ label: '4:3', value: '4:3' },
|
|
29
|
+
{ label: '9:16', value: '9:16' }
|
|
30
|
+
];
|
|
22
31
|
function isResizableType(value) {
|
|
23
32
|
return typeSet.has(value);
|
|
24
33
|
}
|
|
@@ -37,6 +46,69 @@ function parseNumericSize(value) {
|
|
|
37
46
|
const parsed = Number.parseFloat(normalized);
|
|
38
47
|
return Number.isFinite(parsed) ? parsed : null;
|
|
39
48
|
}
|
|
49
|
+
function parseAspectRatio(value) {
|
|
50
|
+
if (typeof value === 'number')
|
|
51
|
+
return Number.isFinite(value) && value > 0 ? value : null;
|
|
52
|
+
if (typeof value !== 'string')
|
|
53
|
+
return null;
|
|
54
|
+
const trimmed = value.trim();
|
|
55
|
+
if (!trimmed)
|
|
56
|
+
return null;
|
|
57
|
+
const ratioMatch = /^([0-9]+(?:\.[0-9]+)?)\s*:\s*([0-9]+(?:\.[0-9]+)?)$/.exec(trimmed);
|
|
58
|
+
if (ratioMatch) {
|
|
59
|
+
const widthPart = Number.parseFloat(ratioMatch[1]);
|
|
60
|
+
const heightPart = Number.parseFloat(ratioMatch[2]);
|
|
61
|
+
if (!Number.isFinite(widthPart) || !Number.isFinite(heightPart))
|
|
62
|
+
return null;
|
|
63
|
+
if (widthPart <= 0 || heightPart <= 0)
|
|
64
|
+
return null;
|
|
65
|
+
return widthPart / heightPart;
|
|
66
|
+
}
|
|
67
|
+
const parsed = Number.parseFloat(trimmed);
|
|
68
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
69
|
+
return null;
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
function formatDecimal(value, precision = 6) {
|
|
73
|
+
return String(Number(value.toFixed(precision)));
|
|
74
|
+
}
|
|
75
|
+
function normalizeAspectRatioAttr(value) {
|
|
76
|
+
if (typeof value === 'number') {
|
|
77
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
78
|
+
return null;
|
|
79
|
+
return formatDecimal(value);
|
|
80
|
+
}
|
|
81
|
+
if (typeof value !== 'string')
|
|
82
|
+
return null;
|
|
83
|
+
const trimmed = value.trim();
|
|
84
|
+
if (!trimmed)
|
|
85
|
+
return null;
|
|
86
|
+
const ratioMatch = /^([0-9]+(?:\.[0-9]+)?)\s*:\s*([0-9]+(?:\.[0-9]+)?)$/.exec(trimmed);
|
|
87
|
+
if (ratioMatch) {
|
|
88
|
+
const widthPart = Number.parseFloat(ratioMatch[1]);
|
|
89
|
+
const heightPart = Number.parseFloat(ratioMatch[2]);
|
|
90
|
+
if (!Number.isFinite(widthPart) || !Number.isFinite(heightPart))
|
|
91
|
+
return null;
|
|
92
|
+
if (widthPart <= 0 || heightPart <= 0)
|
|
93
|
+
return null;
|
|
94
|
+
return `${formatDecimal(widthPart, 4)}:${formatDecimal(heightPart, 4)}`;
|
|
95
|
+
}
|
|
96
|
+
const parsed = Number.parseFloat(trimmed);
|
|
97
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
98
|
+
return null;
|
|
99
|
+
return formatDecimal(parsed);
|
|
100
|
+
}
|
|
101
|
+
function sameAspectRatio(left, right) {
|
|
102
|
+
if (!left && !right)
|
|
103
|
+
return true;
|
|
104
|
+
if (!left || !right)
|
|
105
|
+
return false;
|
|
106
|
+
const leftRatio = parseAspectRatio(left);
|
|
107
|
+
const rightRatio = parseAspectRatio(right);
|
|
108
|
+
if (leftRatio === null || rightRatio === null)
|
|
109
|
+
return false;
|
|
110
|
+
return Math.abs(leftRatio - rightRatio) <= 0.001;
|
|
111
|
+
}
|
|
40
112
|
function normalizeStringAttr(value) {
|
|
41
113
|
if (typeof value !== 'string')
|
|
42
114
|
return null;
|
|
@@ -113,6 +185,15 @@ function resolveStartHeight(kind, node, element) {
|
|
|
113
185
|
return fromAttr;
|
|
114
186
|
return defaultHeight[kind];
|
|
115
187
|
}
|
|
188
|
+
function resolveElementWidth(node, element) {
|
|
189
|
+
const rect = element.getBoundingClientRect();
|
|
190
|
+
if (rect.width > 0)
|
|
191
|
+
return rect.width;
|
|
192
|
+
const fromAttr = parseNumericSize(node.attrs.width);
|
|
193
|
+
if (fromAttr !== null)
|
|
194
|
+
return fromAttr;
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
116
197
|
function resolveTargetElement(view, pos, resizeMeta, node) {
|
|
117
198
|
const nodeDom = view.nodeDOM(pos);
|
|
118
199
|
if (!(nodeDom instanceof HTMLElement))
|
|
@@ -153,7 +234,7 @@ function resolveTargetElement(view, pos, resizeMeta, node) {
|
|
|
153
234
|
nodeDom.querySelector('iframe') ||
|
|
154
235
|
nodeDom);
|
|
155
236
|
}
|
|
156
|
-
function buildResizeAttrs(kind, node, height, imageRatio) {
|
|
237
|
+
function buildResizeAttrs(kind, node, height, imageRatio, aspectRatio = normalizeAspectRatioAttr(node.attrs.aspectRatio)) {
|
|
157
238
|
const attrs = { ...node.attrs };
|
|
158
239
|
const roundedHeight = String(Math.round(height));
|
|
159
240
|
if (kind === 'image') {
|
|
@@ -162,11 +243,11 @@ function buildResizeAttrs(kind, node, height, imageRatio) {
|
|
|
162
243
|
return { ...attrs, width: roundedWidth, height: null };
|
|
163
244
|
}
|
|
164
245
|
if (kind === 'iframe' || kind === 'embed') {
|
|
165
|
-
return { ...attrs, width: attrs.width || '100%', height: roundedHeight };
|
|
246
|
+
return { ...attrs, width: attrs.width || '100%', height: roundedHeight, aspectRatio };
|
|
166
247
|
}
|
|
167
|
-
return { ...attrs, height: roundedHeight };
|
|
248
|
+
return { ...attrs, height: roundedHeight, aspectRatio };
|
|
168
249
|
}
|
|
169
|
-
function createResizeHandleDecoration(nodePos, widgetPos, resizeMeta) {
|
|
250
|
+
function createResizeHandleDecoration(nodePos, widgetPos, resizeMeta, node) {
|
|
170
251
|
return Decoration.widget(widgetPos, () => {
|
|
171
252
|
const anchor = document.createElement('div');
|
|
172
253
|
anchor.className = 'tiptap-media-resize-anchor';
|
|
@@ -175,8 +256,30 @@ function createResizeHandleDecoration(nodePos, widgetPos, resizeMeta) {
|
|
|
175
256
|
button.className = 'tiptap-media-resize-handle';
|
|
176
257
|
button.dataset.resizePos = String(nodePos);
|
|
177
258
|
button.dataset.resizeKind = resizeMeta.kind;
|
|
178
|
-
button.setAttribute('aria-label', 'Resize media height');
|
|
259
|
+
button.setAttribute('aria-label', 'Resize media height (click for aspect ratio)');
|
|
179
260
|
anchor.append(button);
|
|
261
|
+
if (resizeMeta.kind !== 'image') {
|
|
262
|
+
const selectedAspectRatio = normalizeAspectRatioAttr(node.attrs.aspectRatio);
|
|
263
|
+
const toolbar = document.createElement('div');
|
|
264
|
+
toolbar.className = 'tiptap-media-aspect-ratio-toolbar';
|
|
265
|
+
toolbar.setAttribute('role', 'toolbar');
|
|
266
|
+
toolbar.setAttribute('aria-label', 'Aspect ratio presets');
|
|
267
|
+
toolbar.dataset.resizePos = String(nodePos);
|
|
268
|
+
for (const option of aspectRatioOptions) {
|
|
269
|
+
const optionButton = document.createElement('button');
|
|
270
|
+
optionButton.type = 'button';
|
|
271
|
+
optionButton.className = 'tiptap-media-aspect-ratio-option';
|
|
272
|
+
optionButton.dataset.resizePos = String(nodePos);
|
|
273
|
+
optionButton.dataset.aspectRatio = option.value ?? 'auto';
|
|
274
|
+
optionButton.textContent = option.label;
|
|
275
|
+
const isActive = option.value
|
|
276
|
+
? sameAspectRatio(option.value, selectedAspectRatio)
|
|
277
|
+
: !selectedAspectRatio;
|
|
278
|
+
optionButton.setAttribute('aria-pressed', isActive ? 'true' : 'false');
|
|
279
|
+
toolbar.append(optionButton);
|
|
280
|
+
}
|
|
281
|
+
anchor.append(toolbar);
|
|
282
|
+
}
|
|
180
283
|
return anchor;
|
|
181
284
|
}, { side: 1, key: `media-resize-${nodePos}-${resizeMeta.typeName}-${resizeMeta.kind}` });
|
|
182
285
|
}
|
|
@@ -254,9 +357,7 @@ export default Extension.create({
|
|
|
254
357
|
default: false,
|
|
255
358
|
parseHTML: (element) => hasResizeHandler(element.getAttribute('data-resize-handler') ||
|
|
256
359
|
element.getAttribute('resize-handler')),
|
|
257
|
-
renderHTML: (attributes) => hasResizeHandler(attributes.resizeHandler)
|
|
258
|
-
? { 'data-resize-handler': 'true' }
|
|
259
|
-
: {}
|
|
360
|
+
renderHTML: (attributes) => hasResizeHandler(attributes.resizeHandler) ? { 'data-resize-handler': 'true' } : {}
|
|
260
361
|
},
|
|
261
362
|
resizeTarget: {
|
|
262
363
|
default: null,
|
|
@@ -281,6 +382,14 @@ export default Extension.create({
|
|
|
281
382
|
const maxHeight = normalizeNumericAttr(attributes.maxHeight);
|
|
282
383
|
return maxHeight ? { 'data-resize-max-height': maxHeight } : {};
|
|
283
384
|
}
|
|
385
|
+
},
|
|
386
|
+
aspectRatio: {
|
|
387
|
+
default: null,
|
|
388
|
+
parseHTML: (element) => normalizeAspectRatioAttr(element.getAttribute('data-resize-aspect-ratio')),
|
|
389
|
+
renderHTML: (attributes) => {
|
|
390
|
+
const aspectRatio = normalizeAspectRatioAttr(attributes.aspectRatio);
|
|
391
|
+
return aspectRatio ? { 'data-resize-aspect-ratio': aspectRatio } : {};
|
|
392
|
+
}
|
|
284
393
|
}
|
|
285
394
|
}
|
|
286
395
|
}
|
|
@@ -288,6 +397,15 @@ export default Extension.create({
|
|
|
288
397
|
},
|
|
289
398
|
addProseMirrorPlugins() {
|
|
290
399
|
let removeDragListeners = null;
|
|
400
|
+
const closeOpenToolbars = (view, except = null) => {
|
|
401
|
+
view.dom
|
|
402
|
+
.querySelectorAll('.tiptap-media-resize-anchor.is-toolbar-open')
|
|
403
|
+
.forEach((anchor) => {
|
|
404
|
+
if (except && anchor === except)
|
|
405
|
+
return;
|
|
406
|
+
anchor.classList.remove('is-toolbar-open');
|
|
407
|
+
});
|
|
408
|
+
};
|
|
291
409
|
return [
|
|
292
410
|
new Plugin({
|
|
293
411
|
key: pluginKey,
|
|
@@ -328,7 +446,7 @@ export default Extension.create({
|
|
|
328
446
|
const resizeMeta = resolveResizeMeta(node);
|
|
329
447
|
if (!resizeMeta || resizeMeta.kind === 'image' || node.isInline)
|
|
330
448
|
return;
|
|
331
|
-
decorations.push(createResizeHandleDecoration(pos, pos + node.nodeSize, resizeMeta));
|
|
449
|
+
decorations.push(createResizeHandleDecoration(pos, pos + node.nodeSize, resizeMeta, node));
|
|
332
450
|
handled.add(pos);
|
|
333
451
|
});
|
|
334
452
|
}
|
|
@@ -336,7 +454,7 @@ export default Extension.create({
|
|
|
336
454
|
const pos = state.selection.from;
|
|
337
455
|
const resizeMeta = resolveResizeMeta(state.selection.node);
|
|
338
456
|
if (resizeMeta && !handled.has(pos)) {
|
|
339
|
-
decorations.push(createResizeHandleDecoration(pos, pos + state.selection.node.nodeSize, resizeMeta));
|
|
457
|
+
decorations.push(createResizeHandleDecoration(pos, pos + state.selection.node.nodeSize, resizeMeta, state.selection.node));
|
|
340
458
|
}
|
|
341
459
|
}
|
|
342
460
|
if (!decorations.length)
|
|
@@ -349,9 +467,50 @@ export default Extension.create({
|
|
|
349
467
|
return false;
|
|
350
468
|
if (!(event.target instanceof HTMLElement))
|
|
351
469
|
return false;
|
|
470
|
+
const ratioOption = event.target.closest('.tiptap-media-aspect-ratio-option');
|
|
471
|
+
if (ratioOption) {
|
|
472
|
+
event.preventDefault();
|
|
473
|
+
event.stopPropagation();
|
|
474
|
+
const pos = Number.parseInt(ratioOption.dataset.resizePos || '', 10);
|
|
475
|
+
if (!Number.isFinite(pos))
|
|
476
|
+
return true;
|
|
477
|
+
const node = view.state.doc.nodeAt(pos);
|
|
478
|
+
if (!node)
|
|
479
|
+
return true;
|
|
480
|
+
const resizeMeta = resolveResizeMeta(node);
|
|
481
|
+
if (!resizeMeta || resizeMeta.kind === 'image')
|
|
482
|
+
return true;
|
|
483
|
+
const target = resolveTargetElement(view, pos, resizeMeta, node);
|
|
484
|
+
if (!target)
|
|
485
|
+
return true;
|
|
486
|
+
const selectedRatio = ratioOption.dataset.aspectRatio || 'auto';
|
|
487
|
+
const normalizedAspectRatio = selectedRatio === 'auto' ? null : normalizeAspectRatioAttr(selectedRatio);
|
|
488
|
+
if (selectedRatio !== 'auto' && !normalizedAspectRatio)
|
|
489
|
+
return true;
|
|
490
|
+
let nextHeight = resolveStartHeight(resizeMeta.kind, node, target);
|
|
491
|
+
const ratioValue = parseAspectRatio(normalizedAspectRatio);
|
|
492
|
+
if (ratioValue !== null) {
|
|
493
|
+
const width = resolveElementWidth(node, target);
|
|
494
|
+
if (width > 0) {
|
|
495
|
+
nextHeight = clamp(width / ratioValue, resizeMeta.minHeight, resizeMeta.maxHeight);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const nextAttrs = buildResizeAttrs(resizeMeta.kind, node, nextHeight, 1, normalizedAspectRatio);
|
|
499
|
+
const nextWidth = 'width' in nextAttrs ? nextAttrs.width : node.attrs.width;
|
|
500
|
+
const nextAspectRatio = 'aspectRatio' in nextAttrs ? nextAttrs.aspectRatio : null;
|
|
501
|
+
if (nextAttrs.height !== node.attrs.height ||
|
|
502
|
+
nextWidth !== node.attrs.width ||
|
|
503
|
+
nextAspectRatio !== node.attrs.aspectRatio) {
|
|
504
|
+
view.dispatch(view.state.tr.setNodeMarkup(pos, node.type, nextAttrs));
|
|
505
|
+
}
|
|
506
|
+
closeOpenToolbars(view);
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
352
509
|
const handle = event.target.closest('.tiptap-media-resize-handle');
|
|
353
|
-
if (!handle)
|
|
510
|
+
if (!handle) {
|
|
511
|
+
closeOpenToolbars(view);
|
|
354
512
|
return false;
|
|
513
|
+
}
|
|
355
514
|
const pos = Number.parseInt(handle.dataset.resizePos || '', 10);
|
|
356
515
|
if (!Number.isFinite(pos))
|
|
357
516
|
return false;
|
|
@@ -369,6 +528,8 @@ export default Extension.create({
|
|
|
369
528
|
return false;
|
|
370
529
|
event.preventDefault();
|
|
371
530
|
event.stopPropagation();
|
|
531
|
+
const anchor = handle.closest('.tiptap-media-resize-anchor');
|
|
532
|
+
const startX = event.clientX;
|
|
372
533
|
const startY = event.clientY;
|
|
373
534
|
const startHeight = resolveStartHeight(resizeMeta.kind, node, target);
|
|
374
535
|
const imageRatio = resizeMeta.kind === 'image' ? resolveImageRatio(node, target) : 1;
|
|
@@ -377,21 +538,10 @@ export default Extension.create({
|
|
|
377
538
|
let restoreTarget = null;
|
|
378
539
|
let frame = 0;
|
|
379
540
|
let pendingHeight = startHeight;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
resizeProxy.className = 'tiptap-media-resize-proxy';
|
|
385
|
-
resizeProxy.style.height = `${Math.round(startHeight)}px`;
|
|
386
|
-
target.parentElement.insertBefore(resizeProxy, targetElement);
|
|
387
|
-
targetElement.style.display = 'none';
|
|
388
|
-
restoreTarget = () => {
|
|
389
|
-
targetElement.style.display = originalDisplay;
|
|
390
|
-
resizeProxy?.remove();
|
|
391
|
-
resizeProxy = null;
|
|
392
|
-
restoreTarget = null;
|
|
393
|
-
};
|
|
394
|
-
}
|
|
541
|
+
let isDragging = false;
|
|
542
|
+
let appliedDragCursor = false;
|
|
543
|
+
const previousCursor = document.body.style.cursor;
|
|
544
|
+
const previousSelect = document.body.style.userSelect;
|
|
395
545
|
const dispatchHeight = (height) => {
|
|
396
546
|
const current = view.state.doc.nodeAt(pos);
|
|
397
547
|
if (!current || current.type.name !== resizeMeta.typeName)
|
|
@@ -399,19 +549,51 @@ export default Extension.create({
|
|
|
399
549
|
const currentMeta = resolveResizeMeta(current);
|
|
400
550
|
if (!currentMeta)
|
|
401
551
|
return;
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
552
|
+
// Manual drag should unlock fixed aspect ratio.
|
|
553
|
+
const aspectRatioForDrag = null;
|
|
554
|
+
const nextAttrs = buildResizeAttrs(currentMeta.kind, current, height, imageRatio, aspectRatioForDrag);
|
|
555
|
+
const nextWidth = 'width' in nextAttrs
|
|
556
|
+
? nextAttrs.width
|
|
557
|
+
: current.attrs.width;
|
|
558
|
+
const nextAspectRatio = 'aspectRatio' in nextAttrs ? nextAttrs.aspectRatio : null;
|
|
559
|
+
if (nextAttrs.height === current.attrs.height &&
|
|
560
|
+
nextWidth === current.attrs.width &&
|
|
561
|
+
nextAspectRatio === current.attrs.aspectRatio)
|
|
405
562
|
return;
|
|
406
|
-
|
|
407
|
-
|
|
563
|
+
view.dispatch(view.state.tr.setNodeMarkup(pos, current.type, nextAttrs));
|
|
564
|
+
};
|
|
565
|
+
const beginDrag = () => {
|
|
566
|
+
if (isDragging)
|
|
567
|
+
return;
|
|
568
|
+
isDragging = true;
|
|
569
|
+
closeOpenToolbars(view);
|
|
570
|
+
if (shouldShowProxy && target.parentElement) {
|
|
571
|
+
const targetElement = target;
|
|
572
|
+
const originalDisplay = targetElement.style.display;
|
|
573
|
+
resizeProxy = document.createElement('div');
|
|
574
|
+
resizeProxy.className = 'tiptap-media-resize-proxy';
|
|
575
|
+
resizeProxy.style.height = `${Math.round(startHeight)}px`;
|
|
576
|
+
target.parentElement.insertBefore(resizeProxy, targetElement);
|
|
577
|
+
targetElement.style.display = 'none';
|
|
578
|
+
restoreTarget = () => {
|
|
579
|
+
targetElement.style.display = originalDisplay;
|
|
580
|
+
resizeProxy?.remove();
|
|
581
|
+
resizeProxy = null;
|
|
582
|
+
restoreTarget = null;
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
document.body.style.cursor = 'ns-resize';
|
|
586
|
+
document.body.style.userSelect = 'none';
|
|
587
|
+
appliedDragCursor = true;
|
|
408
588
|
};
|
|
409
|
-
const previousCursor = document.body.style.cursor;
|
|
410
|
-
const previousSelect = document.body.style.userSelect;
|
|
411
|
-
document.body.style.cursor = 'ns-resize';
|
|
412
|
-
document.body.style.userSelect = 'none';
|
|
413
589
|
const onMove = (moveEvent) => {
|
|
414
|
-
const
|
|
590
|
+
const deltaX = moveEvent.clientX - startX;
|
|
591
|
+
const deltaY = moveEvent.clientY - startY;
|
|
592
|
+
if (!isDragging && Math.max(Math.abs(deltaX), Math.abs(deltaY)) < 4)
|
|
593
|
+
return;
|
|
594
|
+
if (!isDragging)
|
|
595
|
+
beginDrag();
|
|
596
|
+
const nextHeight = clamp(startHeight + deltaY, resizeMeta.minHeight, resizeMeta.maxHeight);
|
|
415
597
|
pendingHeight = nextHeight;
|
|
416
598
|
if (resizeProxy)
|
|
417
599
|
resizeProxy.style.height = `${Math.round(nextHeight)}px`;
|
|
@@ -426,12 +608,21 @@ export default Extension.create({
|
|
|
426
608
|
cancelAnimationFrame(frame);
|
|
427
609
|
window.removeEventListener('mousemove', onMove);
|
|
428
610
|
window.removeEventListener('mouseup', onUp);
|
|
429
|
-
|
|
430
|
-
|
|
611
|
+
if (appliedDragCursor) {
|
|
612
|
+
document.body.style.cursor = previousCursor;
|
|
613
|
+
document.body.style.userSelect = previousSelect;
|
|
614
|
+
}
|
|
431
615
|
restoreTarget?.();
|
|
432
616
|
removeDragListeners = null;
|
|
433
617
|
};
|
|
434
618
|
const onUp = () => {
|
|
619
|
+
if (!isDragging) {
|
|
620
|
+
const shouldOpen = Boolean(anchor) && !(anchor?.classList.contains('is-toolbar-open') ?? false);
|
|
621
|
+
closeOpenToolbars(view, shouldOpen && anchor ? anchor : null);
|
|
622
|
+
anchor?.classList.toggle('is-toolbar-open', shouldOpen);
|
|
623
|
+
cleanup();
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
435
626
|
if (shouldShowProxy)
|
|
436
627
|
dispatchHeight(pendingHeight);
|
|
437
628
|
cleanup();
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
'data-resize-target',
|
|
82
82
|
'data-resize-min-height',
|
|
83
83
|
'data-resize-max-height',
|
|
84
|
+
'data-resize-aspect-ratio',
|
|
84
85
|
'data-bubble-menu',
|
|
85
86
|
'data-hide-bubble-menu'
|
|
86
87
|
];
|
|
@@ -343,10 +344,13 @@
|
|
|
343
344
|
.editable :global(.tiptap-media-resize-anchor) {
|
|
344
345
|
width: 100%;
|
|
345
346
|
display: flex;
|
|
346
|
-
|
|
347
|
+
flex-direction: column;
|
|
348
|
+
align-items: center;
|
|
347
349
|
margin: 6px 0 2px;
|
|
348
350
|
line-height: 0;
|
|
349
351
|
pointer-events: none;
|
|
352
|
+
position: relative;
|
|
353
|
+
overflow: visible;
|
|
350
354
|
}
|
|
351
355
|
|
|
352
356
|
.editable :global(.tiptap-media-resize-handle) {
|
|
@@ -379,6 +383,56 @@
|
|
|
379
383
|
transform: translateY(1px);
|
|
380
384
|
}
|
|
381
385
|
|
|
386
|
+
.editable :global(.tiptap-media-aspect-ratio-toolbar) {
|
|
387
|
+
display: none;
|
|
388
|
+
align-items: center;
|
|
389
|
+
gap: 4px;
|
|
390
|
+
padding: 4px;
|
|
391
|
+
border: 1px solid var(--primary-light3, rgba(120, 120, 120, 0.4));
|
|
392
|
+
border-radius: 999px;
|
|
393
|
+
background: var(--surface, #fff);
|
|
394
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
|
395
|
+
pointer-events: auto;
|
|
396
|
+
line-height: 1;
|
|
397
|
+
position: absolute;
|
|
398
|
+
top: calc(100% + 6px);
|
|
399
|
+
left: 50%;
|
|
400
|
+
transform: translateX(-50%);
|
|
401
|
+
z-index: 4;
|
|
402
|
+
white-space: nowrap;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.editable
|
|
406
|
+
:global(.tiptap-media-resize-anchor.is-toolbar-open .tiptap-media-aspect-ratio-toolbar) {
|
|
407
|
+
display: flex;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.editable :global(.tiptap-media-aspect-ratio-option) {
|
|
411
|
+
appearance: none;
|
|
412
|
+
-webkit-appearance: none;
|
|
413
|
+
margin: 0;
|
|
414
|
+
padding: 2px 8px;
|
|
415
|
+
border: 0;
|
|
416
|
+
border-radius: 999px;
|
|
417
|
+
background: transparent;
|
|
418
|
+
color: var(--on-surface, #000);
|
|
419
|
+
font-size: 11px;
|
|
420
|
+
font-weight: 600;
|
|
421
|
+
cursor: pointer;
|
|
422
|
+
transition: background-color 0.15s ease;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.editable :global(.tiptap-media-aspect-ratio-option:hover),
|
|
426
|
+
.editable :global(.tiptap-media-aspect-ratio-option:focus-visible) {
|
|
427
|
+
background: var(--primary-light1, rgba(120, 120, 120, 0.14));
|
|
428
|
+
outline: none;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.editable :global(.tiptap-media-aspect-ratio-option[aria-pressed='true']) {
|
|
432
|
+
background: var(--primary-light4, rgba(120, 120, 120, 0.3));
|
|
433
|
+
color: var(--on-primary, #000);
|
|
434
|
+
}
|
|
435
|
+
|
|
382
436
|
.editable :global(.tiptap-media-resize-proxy) {
|
|
383
437
|
width: 100%;
|
|
384
438
|
border-radius: 12px;
|
|
@@ -471,21 +525,58 @@
|
|
|
471
525
|
border-radius: 12px;
|
|
472
526
|
}
|
|
473
527
|
|
|
474
|
-
& :global(.iframe-wrapper)
|
|
475
|
-
|
|
476
|
-
padding-bottom: 12px;
|
|
528
|
+
& :global(.iframe-wrapper),
|
|
529
|
+
& :global(.embed-wrapper) {
|
|
477
530
|
overflow: hidden;
|
|
478
531
|
width: 100%;
|
|
479
|
-
height: 600px;
|
|
480
532
|
border-radius: 12px;
|
|
481
533
|
}
|
|
482
534
|
|
|
483
|
-
& :global(iframe)
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
left: 0;
|
|
535
|
+
& :global(iframe),
|
|
536
|
+
& :global(embed) {
|
|
537
|
+
display: block;
|
|
487
538
|
width: 100%;
|
|
488
|
-
|
|
539
|
+
max-width: 100%;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
& :global([data-resize-aspect-ratio='16:9']) {
|
|
543
|
+
--tiptap-media-aspect-ratio: 16 / 9;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
& :global([data-resize-aspect-ratio='3:2']) {
|
|
547
|
+
--tiptap-media-aspect-ratio: 3 / 2;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
& :global([data-resize-aspect-ratio='21:9']) {
|
|
551
|
+
--tiptap-media-aspect-ratio: 21 / 9;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
& :global([data-resize-aspect-ratio='1:1']) {
|
|
555
|
+
--tiptap-media-aspect-ratio: 1 / 1;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
& :global([data-resize-aspect-ratio='4:3']) {
|
|
559
|
+
--tiptap-media-aspect-ratio: 4 / 3;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
& :global([data-resize-aspect-ratio='9:16']) {
|
|
563
|
+
--tiptap-media-aspect-ratio: 9 / 16;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
& :global(iframe[data-resize-aspect-ratio='16:9']),
|
|
567
|
+
& :global(iframe[data-resize-aspect-ratio='3:2']),
|
|
568
|
+
& :global(iframe[data-resize-aspect-ratio='21:9']),
|
|
569
|
+
& :global(iframe[data-resize-aspect-ratio='1:1']),
|
|
570
|
+
& :global(iframe[data-resize-aspect-ratio='4:3']),
|
|
571
|
+
& :global(iframe[data-resize-aspect-ratio='9:16']),
|
|
572
|
+
& :global(embed[data-resize-aspect-ratio='16:9']),
|
|
573
|
+
& :global(embed[data-resize-aspect-ratio='3:2']),
|
|
574
|
+
& :global(embed[data-resize-aspect-ratio='21:9']),
|
|
575
|
+
& :global(embed[data-resize-aspect-ratio='1:1']),
|
|
576
|
+
& :global(embed[data-resize-aspect-ratio='4:3']),
|
|
577
|
+
& :global(embed[data-resize-aspect-ratio='9:16']) {
|
|
578
|
+
aspect-ratio: var(--tiptap-media-aspect-ratio, auto);
|
|
579
|
+
height: auto;
|
|
489
580
|
}
|
|
490
581
|
}
|
|
491
582
|
</style>
|