@seorii/tiptap 0.3.0-next.8 → 0.3.0
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/index.d.ts +106 -6
- package/dist/i18n/index.js +56 -11
- package/dist/plugin/command/emoji.d.ts +3 -17
- package/dist/plugin/command/emoji.js +51 -24
- package/dist/plugin/command/stores.svelte.d.ts +52 -0
- package/dist/plugin/command/stores.svelte.js +69 -0
- package/dist/plugin/command/suggest.d.ts +6 -19
- package/dist/plugin/command/suggest.js +133 -51
- package/dist/plugin/embed.d.ts +2 -2
- package/dist/plugin/embed.js +5 -1
- package/dist/plugin/image/dragdrop.d.ts +2 -0
- package/dist/plugin/image/dragdrop.js +66 -2
- package/dist/plugin/image/index.js +3 -2
- package/dist/plugin/indent.js +0 -1
- package/dist/plugin/orderedlist/index.d.ts +1 -1
- package/dist/plugin/orderedlist/index.js +1 -1
- package/dist/plugin/orderedlist/{korean.scss → korean.css} +2 -2
- package/dist/plugin/table/index.d.ts +1 -1
- package/dist/plugin/table/index.js +19 -11
- package/dist/plugin/table/style/{cell.scss → cell.css} +6 -5
- package/dist/plugin/table/style/{grip.scss → grip.css} +14 -19
- package/dist/plugin/table/style/resize.css +28 -0
- package/dist/plugin/table/style/{table.scss → table.css} +15 -17
- package/dist/plugin/table/style.css +4 -0
- package/dist/plugin/table/tableCell/index.js +2 -4
- package/dist/plugin/table/tableHeader/index.js +1 -2
- package/dist/tiptap/Bubble.svelte +106 -71
- package/dist/tiptap/Bubble.svelte.d.ts +8 -6
- package/dist/tiptap/Command.svelte +160 -158
- package/dist/tiptap/Command.svelte.d.ts +2 -3
- package/dist/tiptap/Floating.svelte +51 -24
- package/dist/tiptap/Floating.svelte.d.ts +1 -0
- package/dist/tiptap/TipTap.svelte +215 -135
- package/dist/tiptap/TipTap.svelte.d.ts +7 -3
- package/dist/tiptap/ToolbarButton.svelte +30 -10
- package/dist/tiptap/ToolbarButton.svelte.d.ts +10 -6
- package/dist/tiptap/setMath.d.ts +2 -1
- package/dist/tiptap/setMath.js +74 -12
- package/dist/tiptap/tiptap.d.ts +9 -1
- package/dist/tiptap/tiptap.js +170 -16
- package/package.json +63 -57
- package/dist/plugin/command/stores.d.ts +0 -13
- package/dist/plugin/command/stores.js +0 -7
- package/dist/plugin/table/style/resize.scss +0 -26
- package/dist/plugin/table/style.scss +0 -4
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { setContext, untrack } from 'svelte';
|
|
3
3
|
import sanitizeHtml from 'sanitize-html';
|
|
4
4
|
import '@seorii/prosemirror-math/style.css';
|
|
5
5
|
import Bubble from './Bubble.svelte';
|
|
6
6
|
import Floating from './Floating.svelte';
|
|
7
7
|
import Command from './Command.svelte';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
countSlashItems,
|
|
10
|
+
flattenSlashItems,
|
|
11
|
+
normalizeSlashIndex,
|
|
12
|
+
slashState
|
|
13
|
+
} from '../plugin/command/stores.svelte';
|
|
14
|
+
import {
|
|
15
|
+
I18N_CONTEXT,
|
|
16
|
+
setLocale as setI18nLocale,
|
|
17
|
+
translateWithLocale,
|
|
18
|
+
type I18nTranslate
|
|
19
|
+
} from '../i18n';
|
|
10
20
|
import type { UploadFn } from '../plugin/image/dragdrop';
|
|
11
21
|
import { fallbackUpload } from '../plugin/image/dragdrop';
|
|
12
22
|
import { Render } from 'nunui';
|
|
@@ -22,11 +32,13 @@
|
|
|
22
32
|
style?: string;
|
|
23
33
|
blocks?: any[];
|
|
24
34
|
placeholder?: string;
|
|
35
|
+
locale?: string;
|
|
25
36
|
sanitize?: Record<string, any>;
|
|
26
37
|
colors?: string[];
|
|
27
38
|
bubble?: any;
|
|
28
39
|
preloader?: any;
|
|
29
40
|
crossorigin?: 'anonymous' | 'use-credentials';
|
|
41
|
+
codeBlockLanguageLabels?: Record<string, string>;
|
|
30
42
|
};
|
|
31
43
|
|
|
32
44
|
let {
|
|
@@ -39,7 +51,8 @@
|
|
|
39
51
|
imageUpload = fallbackUpload,
|
|
40
52
|
style = '',
|
|
41
53
|
blocks = [],
|
|
42
|
-
placeholder
|
|
54
|
+
placeholder,
|
|
55
|
+
locale,
|
|
43
56
|
sanitize = {},
|
|
44
57
|
colors = [
|
|
45
58
|
'#ef5350', //red
|
|
@@ -54,8 +67,11 @@
|
|
|
54
67
|
bubble = null,
|
|
55
68
|
preloader,
|
|
56
69
|
crossorigin = 'anonymous',
|
|
70
|
+
codeBlockLanguageLabels = {}
|
|
57
71
|
}: Props = $props();
|
|
58
72
|
|
|
73
|
+
const scopedI18n: I18nTranslate = (...args) => translateWithLocale(locale, ...args);
|
|
74
|
+
|
|
59
75
|
const san = (body: string) =>
|
|
60
76
|
sanitizeHtml(body || '', {
|
|
61
77
|
...(sanitize || {}),
|
|
@@ -87,13 +103,18 @@
|
|
|
87
103
|
}
|
|
88
104
|
});
|
|
89
105
|
|
|
90
|
-
const tiptap = $state({ v: null as any });
|
|
106
|
+
const tiptap = $state({ v: null as any, c: 0 });
|
|
91
107
|
setContext('editor', tiptap);
|
|
108
|
+
setContext(I18N_CONTEXT, scopedI18n);
|
|
92
109
|
let element: Element,
|
|
93
110
|
fullscreen = $state(false),
|
|
94
111
|
mounted = $state(false),
|
|
95
112
|
last = $state('');
|
|
96
113
|
|
|
114
|
+
$effect(() => {
|
|
115
|
+
setI18nLocale(locale);
|
|
116
|
+
});
|
|
117
|
+
|
|
97
118
|
$effect(() => {
|
|
98
119
|
if (tiptap.v) tiptap.v.setEditable(editable);
|
|
99
120
|
});
|
|
@@ -111,11 +132,16 @@
|
|
|
111
132
|
Promise.all([import('./tiptap'), import('@justinribeiro/lite-youtube')]).then(
|
|
112
133
|
([{ default: tt }]) => {
|
|
113
134
|
if (!untrack(() => mounted)) return;
|
|
135
|
+
const editorPlaceholder = placeholder ?? scopedI18n('placeholder');
|
|
114
136
|
tiptap.v = ref = tt(element, r, {
|
|
115
|
-
placeholder,
|
|
137
|
+
placeholder: editorPlaceholder,
|
|
116
138
|
editable,
|
|
117
|
-
onTransaction: () =>
|
|
139
|
+
onTransaction: () => {
|
|
140
|
+
tiptap.v = ref = tiptap.v;
|
|
141
|
+
tiptap.c++;
|
|
142
|
+
},
|
|
118
143
|
crossorigin,
|
|
144
|
+
codeBlockLanguageLabels,
|
|
119
145
|
...options
|
|
120
146
|
});
|
|
121
147
|
tiptap.v.on('update', ({ editor: tiptap }: any) => {
|
|
@@ -147,29 +173,35 @@
|
|
|
147
173
|
tiptap.v?.commands?.setContent?.(body);
|
|
148
174
|
});
|
|
149
175
|
|
|
150
|
-
let selectedIndex = $state(0);
|
|
151
|
-
$effect(() => {
|
|
152
|
-
if (!slashVisible) selectedIndex = 0;
|
|
153
|
-
});
|
|
154
|
-
|
|
155
176
|
function handleKeydown(event: KeyboardEvent) {
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
177
|
+
if (event.defaultPrevented) return true;
|
|
178
|
+
if (!slashState.visible) return false;
|
|
179
|
+
const count = countSlashItems();
|
|
180
|
+
if (!count) return false;
|
|
181
|
+
|
|
182
|
+
if (event.key === 'Tab') {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
slashState.selectedIndex += event.shiftKey ? -1 : 1;
|
|
185
|
+
normalizeSlashIndex();
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
159
189
|
if (event.key === 'ArrowUp') {
|
|
160
190
|
event.preventDefault();
|
|
161
|
-
selectedIndex
|
|
191
|
+
slashState.selectedIndex -= 1;
|
|
192
|
+
normalizeSlashIndex();
|
|
162
193
|
return true;
|
|
163
194
|
}
|
|
164
195
|
if (event.key === 'ArrowDown') {
|
|
165
196
|
event.preventDefault();
|
|
166
|
-
selectedIndex
|
|
197
|
+
slashState.selectedIndex += 1;
|
|
198
|
+
normalizeSlashIndex();
|
|
167
199
|
return true;
|
|
168
200
|
}
|
|
169
201
|
|
|
170
202
|
if (event.key === 'Enter') {
|
|
171
203
|
event.preventDefault();
|
|
172
|
-
selectItem(selectedIndex);
|
|
204
|
+
selectItem(slashState.selectedIndex);
|
|
173
205
|
return true;
|
|
174
206
|
}
|
|
175
207
|
|
|
@@ -177,13 +209,10 @@
|
|
|
177
209
|
}
|
|
178
210
|
|
|
179
211
|
function selectItem(index: number) {
|
|
180
|
-
const item = (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
let range = $slashProps.range;
|
|
185
|
-
item.command({ editor: tiptap.v, range });
|
|
186
|
-
}
|
|
212
|
+
const item = flattenSlashItems()[index];
|
|
213
|
+
const { editor, range } = slashState.props;
|
|
214
|
+
if (!item || !editor || !range) return;
|
|
215
|
+
item.command({ editor, range });
|
|
187
216
|
}
|
|
188
217
|
</script>
|
|
189
218
|
|
|
@@ -204,7 +233,7 @@
|
|
|
204
233
|
{/if}
|
|
205
234
|
</div>
|
|
206
235
|
{#if editable}
|
|
207
|
-
<Command
|
|
236
|
+
<Command />
|
|
208
237
|
<Floating />
|
|
209
238
|
{/if}
|
|
210
239
|
{#if editable || mark}
|
|
@@ -214,112 +243,163 @@
|
|
|
214
243
|
{/if}
|
|
215
244
|
</main>
|
|
216
245
|
|
|
217
|
-
<style>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.editable :global(.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
div > :global(div)
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
246
|
+
<style>
|
|
247
|
+
main {
|
|
248
|
+
position: relative;
|
|
249
|
+
overscroll-behavior: none;
|
|
250
|
+
--shadow:
|
|
251
|
+
0 1px 2px rgba(127, 127, 127, 0.07), 0 2px 4px rgba(127, 127, 127, 0.07),
|
|
252
|
+
0 4px 8px rgba(127, 127, 127, 0.07), 0 8px 16px rgba(127, 127, 127, 0.07),
|
|
253
|
+
0 16px 32px rgba(127, 127, 127, 0.07), 0 32px 64px rgba(127, 127, 127, 0.07);
|
|
254
|
+
&.fullscreen {
|
|
255
|
+
z-index: 999999999;
|
|
256
|
+
position: fixed;
|
|
257
|
+
top: 0;
|
|
258
|
+
left: 0;
|
|
259
|
+
right: 0;
|
|
260
|
+
bottom: 0;
|
|
261
|
+
background: var(--surface);
|
|
262
|
+
padding: 82px 12px 12px 12px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
& .wrapper {
|
|
266
|
+
position: relative;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
main :global(.tiptap-code-block-toolbar) {
|
|
271
|
+
position: absolute;
|
|
272
|
+
top: 8px;
|
|
273
|
+
right: 8px;
|
|
274
|
+
z-index: 1;
|
|
275
|
+
display: flex;
|
|
276
|
+
justify-content: flex-end;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
main:not(.editable) :global(.tiptap-code-block-toolbar) {
|
|
280
|
+
visibility: hidden;
|
|
281
|
+
pointer-events: none;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.target > :global(div) > :global(*:first-child) {
|
|
285
|
+
margin-top: 0 !important;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.target > :global(div) > :global(*:last-child) {
|
|
289
|
+
margin-bottom: 0 !important;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.editable :global(.ProseMirror-selectednode img) {
|
|
293
|
+
transition: all 0.2s ease-in-out;
|
|
294
|
+
filter: drop-shadow(0 0 0.75rem var(--primary-light13));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.editable :global(.iframe-wrapper.ProseMirror-selectednode) {
|
|
298
|
+
outline: 3px solid var(--primary);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.editable :global(lite-youtube.ProseMirror-selectednode) {
|
|
302
|
+
outline: 3px solid var(--primary);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
div > :global(div) {
|
|
306
|
+
outline: none !important;
|
|
307
|
+
& :global(.ProseMirror) :global(p.is-editor-empty:first-child::before) {
|
|
308
|
+
color: var(--on-surface, #000);
|
|
309
|
+
opacity: 0.7;
|
|
310
|
+
content: attr(data-placeholder);
|
|
311
|
+
float: left;
|
|
312
|
+
height: 0;
|
|
313
|
+
pointer-events: none;
|
|
314
|
+
transition: 0.2s opacity ease-in-out;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
& :global(.ProseMirror-focused) :global(p.is-editor-empty:first-child::before) {
|
|
318
|
+
opacity: 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
& :global(a) {
|
|
322
|
+
cursor: pointer;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
& :global(img) {
|
|
326
|
+
transition: all 0.2s ease-in-out;
|
|
327
|
+
max-width: 100%;
|
|
328
|
+
border-radius: 12px;
|
|
329
|
+
position: relative;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
& :global(code.inline) {
|
|
333
|
+
background: var(--primary-light1);
|
|
334
|
+
padding: 2px 4px;
|
|
335
|
+
border-radius: 4px;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
& :global(pre) {
|
|
339
|
+
background: var(--primary-light1);
|
|
340
|
+
padding: 12px;
|
|
341
|
+
border-radius: 12px;
|
|
342
|
+
max-width: 100%;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
& :global(.tiptap-code-block) {
|
|
346
|
+
max-width: 100%;
|
|
347
|
+
position: relative;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
& :global(.tiptap-code-block-language) {
|
|
351
|
+
padding: 2px 6px;
|
|
352
|
+
border-radius: 8px;
|
|
353
|
+
border: 1px solid var(--primary-light2, #ddd);
|
|
354
|
+
outline: 1px solid transparent;
|
|
355
|
+
outline-offset: 0;
|
|
356
|
+
background: var(--surface, #fff);
|
|
357
|
+
color: var(--on-surface, #000);
|
|
358
|
+
font-size: 0.75em;
|
|
359
|
+
|
|
360
|
+
&:focus,
|
|
361
|
+
&:focus-visible {
|
|
362
|
+
outline-color: var(--primary-light9, #89a2d9);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
& :global(table) {
|
|
367
|
+
border-collapse: collapse;
|
|
368
|
+
width: 100%;
|
|
369
|
+
margin: 8px 0;
|
|
370
|
+
border: 1px solid var(--primary-light1);
|
|
371
|
+
border-radius: 12px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
& :global(th),
|
|
375
|
+
& :global(td) {
|
|
376
|
+
padding: 8px;
|
|
377
|
+
border: 1px solid var(--primary-light1);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
& :global(.math-render) {
|
|
381
|
+
cursor: initial;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
& :global(lite-youtube) {
|
|
385
|
+
border-radius: 12px;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
& :global(.iframe-wrapper) {
|
|
389
|
+
position: relative;
|
|
390
|
+
padding-bottom: 12px;
|
|
391
|
+
overflow: hidden;
|
|
392
|
+
width: 100%;
|
|
393
|
+
height: 600px;
|
|
394
|
+
border-radius: 12px;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
& :global(iframe) {
|
|
398
|
+
position: absolute;
|
|
399
|
+
top: 0;
|
|
400
|
+
left: 0;
|
|
401
|
+
width: 100%;
|
|
402
|
+
height: 100%;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@seorii/prosemirror-math/style.css';
|
|
2
2
|
import type { UploadFn } from '../plugin/image/dragdrop';
|
|
3
|
-
|
|
3
|
+
type Props = {
|
|
4
4
|
body: string;
|
|
5
5
|
editable?: boolean;
|
|
6
6
|
mark?: boolean;
|
|
@@ -11,10 +11,14 @@ declare const TipTap: import("svelte").Component<{
|
|
|
11
11
|
style?: string;
|
|
12
12
|
blocks?: any[];
|
|
13
13
|
placeholder?: string;
|
|
14
|
+
locale?: string;
|
|
14
15
|
sanitize?: Record<string, any>;
|
|
15
16
|
colors?: string[];
|
|
16
17
|
bubble?: any;
|
|
17
18
|
preloader?: any;
|
|
18
|
-
crossorigin?:
|
|
19
|
-
|
|
19
|
+
crossorigin?: 'anonymous' | 'use-credentials';
|
|
20
|
+
codeBlockLanguageLabels?: Record<string, string>;
|
|
21
|
+
};
|
|
22
|
+
declare const TipTap: import("svelte").Component<Props, {}, "body" | "ref" | "loaded">;
|
|
23
|
+
type TipTap = ReturnType<typeof TipTap>;
|
|
20
24
|
export default TipTap;
|
|
@@ -2,36 +2,56 @@
|
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
3
|
import { Button, IconButton, Render } from 'nunui';
|
|
4
4
|
|
|
5
|
-
const editor = getContext<{ v: any }>('editor');
|
|
5
|
+
const editor = getContext<{ v: any; c: number }>('editor');
|
|
6
6
|
const tiptap = $derived(editor.v);
|
|
7
7
|
|
|
8
|
+
type Props = {
|
|
9
|
+
prop?: string;
|
|
10
|
+
attrs?: Record<string, unknown>;
|
|
11
|
+
label?: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
methodName?: string;
|
|
14
|
+
tooltip?: string | Record<string, any>;
|
|
15
|
+
handler?: (() => void) | null;
|
|
16
|
+
children?: any;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
|
|
8
20
|
let {
|
|
9
21
|
prop = '',
|
|
10
|
-
attrs =
|
|
22
|
+
attrs = {},
|
|
11
23
|
label = '',
|
|
12
24
|
icon = '',
|
|
13
25
|
methodName = 'toggle' + prop.charAt(0).toUpperCase() + prop.slice(1),
|
|
14
26
|
tooltip,
|
|
15
|
-
handler,
|
|
27
|
+
handler = null,
|
|
28
|
+
children,
|
|
16
29
|
...rest
|
|
17
|
-
} = $props();
|
|
30
|
+
}: Props = $props();
|
|
18
31
|
|
|
19
|
-
const isActive = $derived(() => {
|
|
20
|
-
|
|
32
|
+
const isActive = $derived.by(() => {
|
|
33
|
+
// Recompute active styles on every editor transaction (selection/mark changes)
|
|
34
|
+
editor.c;
|
|
35
|
+
return !!(prop && tiptap?.isActive(prop, attrs));
|
|
21
36
|
});
|
|
22
37
|
|
|
23
38
|
function toggle() {
|
|
24
39
|
if (!tiptap) return;
|
|
25
|
-
//tiptap.chain().focus().clearNodes().run()
|
|
26
40
|
if (handler) return handler();
|
|
27
|
-
setTimeout(() =>
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
const chain = tiptap.chain().focus() as Record<
|
|
43
|
+
string,
|
|
44
|
+
(attrs?: unknown) => { run?: () => void }
|
|
45
|
+
>;
|
|
46
|
+
chain[methodName]?.(attrs)?.run?.();
|
|
47
|
+
}, 0);
|
|
28
48
|
}
|
|
29
49
|
</script>
|
|
30
50
|
|
|
31
51
|
{#if icon}
|
|
32
|
-
<IconButton size="1.2em" {icon} active={isActive
|
|
52
|
+
<IconButton size="1.2em" {icon} active={isActive} onclick={toggle} {tooltip} tabindex={0} />
|
|
33
53
|
{:else}
|
|
34
|
-
<Button outlined={!isActive
|
|
54
|
+
<Button outlined={!isActive} onclick={handler || toggle} small {...rest}>
|
|
35
55
|
{label}
|
|
36
56
|
<Render it={children} />
|
|
37
57
|
</Button>
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
type Props = {
|
|
2
2
|
prop?: string;
|
|
3
|
-
attrs?: string
|
|
3
|
+
attrs?: Record<string, unknown>;
|
|
4
4
|
label?: string;
|
|
5
5
|
icon?: string;
|
|
6
|
-
methodName?:
|
|
7
|
-
tooltip
|
|
8
|
-
handler
|
|
9
|
-
|
|
6
|
+
methodName?: string;
|
|
7
|
+
tooltip?: string | Record<string, any>;
|
|
8
|
+
handler?: (() => void) | null;
|
|
9
|
+
children?: any;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
declare const ToolbarButton: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type ToolbarButton = ReturnType<typeof ToolbarButton>;
|
|
10
14
|
export default ToolbarButton;
|
package/dist/tiptap/setMath.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Editor } from '@tiptap/core';
|
|
2
|
+
export default function setMath(tiptap: Editor): void;
|
package/dist/tiptap/setMath.js
CHANGED
|
@@ -1,17 +1,79 @@
|
|
|
1
|
+
import { NodeSelection } from '@tiptap/pm/state';
|
|
2
|
+
const pushUniqueTarget = (targets, from, to, text) => {
|
|
3
|
+
if (targets.some((target) => target.from === from && target.to === to))
|
|
4
|
+
return;
|
|
5
|
+
targets.push({ from, to, text });
|
|
6
|
+
};
|
|
7
|
+
const collectMathTargets = (state, mathInline) => {
|
|
8
|
+
const targets = [];
|
|
9
|
+
const { selection } = state;
|
|
10
|
+
if (selection instanceof NodeSelection && selection.node.type === mathInline) {
|
|
11
|
+
pushUniqueTarget(targets, selection.from, selection.to, selection.node.textContent);
|
|
12
|
+
}
|
|
13
|
+
if (selection.$from.parent.type === mathInline) {
|
|
14
|
+
const depth = selection.$from.depth;
|
|
15
|
+
const from = selection.$from.before(depth);
|
|
16
|
+
const to = selection.$from.after(depth);
|
|
17
|
+
pushUniqueTarget(targets, from, to, selection.$from.parent.textContent);
|
|
18
|
+
}
|
|
19
|
+
state.doc.nodesBetween(selection.from, selection.to, (node, position) => {
|
|
20
|
+
if (node.type !== mathInline)
|
|
21
|
+
return;
|
|
22
|
+
pushUniqueTarget(targets, position, position + node.nodeSize, node.textContent);
|
|
23
|
+
return false;
|
|
24
|
+
});
|
|
25
|
+
return targets;
|
|
26
|
+
};
|
|
27
|
+
const unwrapMath = ({ state, tr }, mathInline) => {
|
|
28
|
+
const targets = collectMathTargets(state, mathInline);
|
|
29
|
+
if (!targets.length)
|
|
30
|
+
return false;
|
|
31
|
+
for (const { from, to, text } of targets.sort((a, b) => b.from - a.from)) {
|
|
32
|
+
if (!text.length) {
|
|
33
|
+
tr.delete(from, to);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
tr.replaceWith(from, to, state.schema.text(text));
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
const wrapSelectionAsMath = ({ state, tr }, mathInline) => {
|
|
41
|
+
const { selection } = state;
|
|
42
|
+
if (selection.empty)
|
|
43
|
+
return false;
|
|
44
|
+
const targets = [];
|
|
45
|
+
state.doc.nodesBetween(selection.from, selection.to, (node, position) => {
|
|
46
|
+
if (!node.isTextblock)
|
|
47
|
+
return;
|
|
48
|
+
const contentFrom = position + 1;
|
|
49
|
+
const contentTo = position + node.nodeSize - 1;
|
|
50
|
+
const from = Math.max(selection.from, contentFrom);
|
|
51
|
+
const to = Math.min(selection.to, contentTo);
|
|
52
|
+
if (from >= to)
|
|
53
|
+
return;
|
|
54
|
+
const text = state.doc.textBetween(from, to, '');
|
|
55
|
+
if (!text.length)
|
|
56
|
+
return;
|
|
57
|
+
targets.push({ from, to, text });
|
|
58
|
+
});
|
|
59
|
+
if (!targets.length)
|
|
60
|
+
return false;
|
|
61
|
+
for (const { from, to, text } of targets.sort((a, b) => b.from - a.from)) {
|
|
62
|
+
const newNode = mathInline.create(null, state.schema.text(text));
|
|
63
|
+
tr.replaceWith(from, to, newNode);
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
};
|
|
1
67
|
export default function setMath(tiptap) {
|
|
2
|
-
const { selection } = tiptap.state;
|
|
3
68
|
tiptap
|
|
4
69
|
.chain()
|
|
5
|
-
.command((
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const newNode = state.schema.nodes.math_inline.create(null, state.schema.text(updatedText));
|
|
14
|
-
tr = tr.replaceWith(startPosition, endPosition, newNode);
|
|
15
|
-
}))
|
|
70
|
+
.command((props) => {
|
|
71
|
+
const mathInline = props.state.schema.nodes.math_inline;
|
|
72
|
+
if (!mathInline || props.state.selection.empty)
|
|
73
|
+
return false;
|
|
74
|
+
if (unwrapMath(props, mathInline))
|
|
75
|
+
return true;
|
|
76
|
+
return wrapSelectionAsMath(props, mathInline);
|
|
77
|
+
})
|
|
16
78
|
.run();
|
|
17
79
|
}
|
package/dist/tiptap/tiptap.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import { Editor } from '@tiptap/core';
|
|
2
|
-
|
|
2
|
+
type CodeBlockLanguageLabelMap = Record<string, string>;
|
|
3
|
+
type CrossOrigin = 'anonymous' | 'use-credentials' | undefined;
|
|
4
|
+
declare const _default: (element: Element, content: string, { placeholder, plugins, crossorigin, codeBlockLanguageLabels, ...props }?: {
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
plugins?: any[];
|
|
7
|
+
crossorigin?: CrossOrigin;
|
|
8
|
+
codeBlockLanguageLabels?: CodeBlockLanguageLabelMap;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}) => Editor;
|
|
3
11
|
export default _default;
|