@seorii/tiptap 0.2.22 → 0.3.0-next.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/plugin/table/util.d.ts +2 -2
- package/dist/tiptap/Bubble.svelte +171 -92
- package/dist/tiptap/Bubble.svelte.d.ts +2 -9
- package/dist/tiptap/Command.svelte +125 -59
- package/dist/tiptap/Command.svelte.d.ts +1 -3
- package/dist/tiptap/Floating.svelte +67 -41
- package/dist/tiptap/TipTap.svelte +205 -132
- package/dist/tiptap/TipTap.svelte.d.ts +2 -23
- package/dist/tiptap/ToolbarButton.svelte +22 -18
- package/dist/tiptap/ToolbarButton.svelte.d.ts +2 -13
- package/dist/tiptap/tiptap.d.ts +1 -1
- package/dist/tiptap/tiptap.js +87 -76
- package/package.json +53 -53
- package/dist/plugin/command/stores.d.ts +0 -14
|
@@ -1,45 +1,71 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { FloatingMenu } from 'svelte-tiptap';
|
|
3
|
+
import { getContext } from 'svelte';
|
|
4
|
+
import { IconButton, List, OneLine, Paper } from 'nunui';
|
|
5
|
+
import ToolbarButton from './ToolbarButton.svelte';
|
|
6
|
+
import i18n from '../i18n';
|
|
7
|
+
|
|
8
|
+
const editor = getContext<{ v: any }>('editor');
|
|
9
|
+
const tiptap = $derived(editor.v);
|
|
7
10
|
</script>
|
|
8
11
|
|
|
9
|
-
{#if
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
12
|
+
{#if tiptap}
|
|
13
|
+
<FloatingMenu editor={tiptap} tippyOptions={{ animation: 'fade', duration: [200, 50] }}>
|
|
14
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
15
|
+
<main onmousedown={() => setTimeout(() => tiptap.commands.focus())}>
|
|
16
|
+
<span>
|
|
17
|
+
{i18n('newLineInfo')}
|
|
18
|
+
</span>
|
|
19
|
+
<Paper bl hover width="160px">
|
|
20
|
+
{#snippet target()}
|
|
21
|
+
<IconButton size="1.2em" icon="text_fields" />
|
|
22
|
+
{/snippet}
|
|
23
|
+
<div style="margin: -6px">
|
|
24
|
+
<List>
|
|
25
|
+
<OneLine
|
|
26
|
+
icon="counter_1"
|
|
27
|
+
title="{i18n('title')} 1"
|
|
28
|
+
onclick={() => tiptap.commands.setHeading({ level: 1 })}
|
|
29
|
+
/>
|
|
30
|
+
<OneLine
|
|
31
|
+
icon="counter_2"
|
|
32
|
+
title="{i18n('title')} 2"
|
|
33
|
+
onclick={() => tiptap.commands.setHeading({ level: 2 })}
|
|
34
|
+
/>
|
|
35
|
+
<OneLine
|
|
36
|
+
icon="counter_3"
|
|
37
|
+
title="{i18n('title')} 3"
|
|
38
|
+
onclick={() => tiptap.commands.setHeading({ level: 3 })}
|
|
39
|
+
/>
|
|
40
|
+
<OneLine
|
|
41
|
+
icon="segment"
|
|
42
|
+
title={i18n('paragraph')}
|
|
43
|
+
onclick={() => tiptap.commands.setParagraph()}
|
|
44
|
+
/>
|
|
45
|
+
</List>
|
|
46
|
+
</div>
|
|
47
|
+
</Paper>
|
|
48
|
+
<ToolbarButton icon="format_bold" prop="bold" />
|
|
49
|
+
<ToolbarButton icon="format_italic" prop="italic" />
|
|
50
|
+
<ToolbarButton icon="format_strikethrough" prop="strike" />
|
|
51
|
+
<ToolbarButton icon="format_underlined" prop="underline" />
|
|
52
|
+
<ToolbarButton
|
|
53
|
+
icon="functions"
|
|
54
|
+
handler={() => {
|
|
55
|
+
const end = tiptap.state.selection.$to.pos;
|
|
56
|
+
tiptap
|
|
57
|
+
.chain()
|
|
58
|
+
.focus()
|
|
59
|
+
.insertContent({
|
|
60
|
+
type: 'math_inline'
|
|
61
|
+
})
|
|
62
|
+
.insertContent(' ')
|
|
63
|
+
.run();
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
<ToolbarButton icon="code" prop="code" />
|
|
67
|
+
</main>
|
|
68
|
+
</FloatingMenu>
|
|
43
69
|
{/if}
|
|
44
70
|
|
|
45
71
|
<style>span {
|
|
@@ -54,4 +80,4 @@ main {
|
|
|
54
80
|
}
|
|
55
81
|
main > :global(*) {
|
|
56
82
|
margin-right: 4px;
|
|
57
|
-
}</style>
|
|
83
|
+
}</style>
|
|
@@ -1,126 +1,203 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import sanitizeHtml from 'sanitize-html';
|
|
5
|
-
import '@seorii/prosemirror-math/style.css';
|
|
6
|
-
import Bubble from './Bubble.svelte';
|
|
7
|
-
import Floating from './Floating.svelte';
|
|
8
|
-
import Command from './Command.svelte';
|
|
9
|
-
import { slashItems, slashProps, slashVisible } from '../plugin/command/stores';
|
|
10
|
-
import i18n from '../i18n';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { browser } from '$app/environment';
|
|
3
|
+
import { onMount, onDestroy, setContext } from 'svelte';
|
|
4
|
+
import sanitizeHtml from 'sanitize-html';
|
|
5
|
+
import '@seorii/prosemirror-math/style.css';
|
|
6
|
+
import Bubble from './Bubble.svelte';
|
|
7
|
+
import Floating from './Floating.svelte';
|
|
8
|
+
import Command from './Command.svelte';
|
|
9
|
+
import { slashItems, slashProps, slashVisible } from '../plugin/command/stores';
|
|
10
|
+
import i18n from '../i18n';
|
|
11
|
+
import type { UploadFn } from '../plugin/image/dragdrop';
|
|
12
|
+
import { fallbackUpload } from '../plugin/image/dragdrop';
|
|
13
|
+
import { Render } from 'nunui';
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
body: string;
|
|
17
|
+
editable: boolean;
|
|
18
|
+
mark: boolean;
|
|
19
|
+
ref: any;
|
|
20
|
+
options: Record<string, any>;
|
|
21
|
+
loaded: boolean;
|
|
22
|
+
imageUpload: UploadFn;
|
|
23
|
+
style: string;
|
|
24
|
+
blocks: any[];
|
|
25
|
+
placeholder: string;
|
|
26
|
+
sanitize: Record<string, any>;
|
|
27
|
+
colors: string[];
|
|
28
|
+
bubble?: any;
|
|
29
|
+
preloader?: any;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
body = $bindable(''),
|
|
34
|
+
editable = false,
|
|
35
|
+
mark = false,
|
|
36
|
+
ref = null,
|
|
37
|
+
options = {},
|
|
38
|
+
loaded = false,
|
|
39
|
+
imageUpload = fallbackUpload,
|
|
40
|
+
style = '',
|
|
41
|
+
blocks = [],
|
|
42
|
+
placeholder = i18n('placeholder'),
|
|
43
|
+
sanitize = {},
|
|
44
|
+
colors = [
|
|
45
|
+
'#ef5350', //red
|
|
46
|
+
'#ec407a', //pink
|
|
47
|
+
'#ff7043', //orange
|
|
48
|
+
'#daca3b', //yellow
|
|
49
|
+
'#8bc34a', //green
|
|
50
|
+
'#2196f3', //blue
|
|
51
|
+
'#3f51b5', //blue
|
|
52
|
+
'#ab47bc' //purple
|
|
53
|
+
],
|
|
54
|
+
bubble = null,
|
|
55
|
+
preloader
|
|
56
|
+
}: Props = $props();
|
|
57
|
+
|
|
58
|
+
const san = (body: string) =>
|
|
59
|
+
sanitizeHtml(body, {
|
|
60
|
+
...(sanitize || {}),
|
|
61
|
+
allowedTags: sanitizeHtml.defaults.allowedTags.concat([
|
|
62
|
+
'img',
|
|
63
|
+
'math-inline',
|
|
64
|
+
'math-node',
|
|
65
|
+
'iframe',
|
|
66
|
+
'lite-youtube',
|
|
67
|
+
'blockquote',
|
|
68
|
+
'embed',
|
|
69
|
+
'mark',
|
|
70
|
+
'code',
|
|
71
|
+
...(sanitize.allowedTags || [])
|
|
72
|
+
]),
|
|
73
|
+
allowedStyles: '*' as any,
|
|
74
|
+
allowedAttributes: {
|
|
75
|
+
'*': ['style', 'class'],
|
|
76
|
+
a: ['href', 'name', 'target'],
|
|
77
|
+
img: ['src', 'srcset', 'alt', 'title', 'width', 'height', 'loading'],
|
|
78
|
+
iframe: ['src', 'width', 'height', 'frameborder', 'allowfullscreen'],
|
|
79
|
+
th: ['colwidth', 'colspan', 'rowspan'],
|
|
80
|
+
td: ['colwidth', 'colspan', 'rowspan'],
|
|
81
|
+
'lite-youtube': ['videoid', 'params', 'nocookie', 'title', 'provider'],
|
|
82
|
+
embed: ['src', 'type', 'frameborder', 'allowfullscreen'],
|
|
83
|
+
mark: ['style', 'data-color'],
|
|
84
|
+
code: ['class'],
|
|
85
|
+
...(sanitize.allowedAttributes || [])
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const tiptap = $state({ v: null as any });
|
|
90
|
+
setContext('editor', tiptap);
|
|
91
|
+
let element: Element,
|
|
92
|
+
fullscreen = $state(false),
|
|
93
|
+
mounted = $state(false),
|
|
94
|
+
last = $state('');
|
|
95
|
+
|
|
96
|
+
$effect(() => {
|
|
97
|
+
if (tiptap.v) tiptap.v.setEditable(editable);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
$effect(() => {
|
|
101
|
+
if (browser) {
|
|
102
|
+
(window as any).__image_uploader = imageUpload;
|
|
103
|
+
(window as any).__tiptap_blocks = blocks;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (browser)
|
|
108
|
+
onMount(() => {
|
|
109
|
+
body = last = san(body);
|
|
110
|
+
mounted = true;
|
|
111
|
+
Promise.all([import('./tiptap'), import('@justinribeiro/lite-youtube')]).then(
|
|
112
|
+
([{ default: tt }]) => {
|
|
113
|
+
if (!mounted) return;
|
|
114
|
+
tiptap.v = ref = tt(element, body, {
|
|
115
|
+
placeholder,
|
|
116
|
+
editable,
|
|
117
|
+
onTransaction: () => (tiptap.v = ref = tiptap.v),
|
|
118
|
+
...options
|
|
119
|
+
});
|
|
120
|
+
tiptap.v.on('update', ({ editor: tiptap }: any) => {
|
|
121
|
+
let content = tiptap.getHTML(),
|
|
122
|
+
json = tiptap.getJSON().content;
|
|
123
|
+
if (
|
|
124
|
+
Array.isArray(json) &&
|
|
125
|
+
json.length === 1 &&
|
|
126
|
+
json[0].type === 'paragraph' &&
|
|
127
|
+
!json[0].hasOwnProperty('content')
|
|
128
|
+
)
|
|
129
|
+
content = null;
|
|
130
|
+
body = last = content;
|
|
131
|
+
});
|
|
132
|
+
loaded = true;
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
onDestroy(() => {
|
|
138
|
+
mounted = false;
|
|
139
|
+
tiptap.v?.destroy?.();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
$effect.pre(() => {
|
|
143
|
+
if (last === body) return;
|
|
144
|
+
body = san(body);
|
|
145
|
+
tiptap.v?.commands?.setContent?.(body);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
let selectedIndex = $state(0);
|
|
149
|
+
$effect(() => {
|
|
150
|
+
if (!slashVisible) selectedIndex = 0;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
154
|
+
if (!$slashVisible) return;
|
|
155
|
+
let count = $slashItems.length;
|
|
156
|
+
if ($slashItems[0]?.list) count = $slashItems.reduce((acc, item) => acc + item.list.length, 0);
|
|
157
|
+
if (event.key === 'ArrowUp') {
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
selectedIndex = (selectedIndex + count - 1) % count;
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (event.key === 'ArrowDown') {
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
selectedIndex = (selectedIndex + 1) % count;
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (event.key === 'Enter') {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
selectItem(selectedIndex);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function selectItem(index) {
|
|
178
|
+
const item = $slashItems[0]?.list
|
|
179
|
+
? $slashItems.map((i) => i.list).flat()[index]
|
|
180
|
+
: $slashItems[index];
|
|
181
|
+
if (item) {
|
|
182
|
+
let range = $slashProps.range;
|
|
183
|
+
item.command({ editor: tiptap.v, range });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
114
186
|
</script>
|
|
115
187
|
|
|
116
|
-
<main class:fullscreen class:editable>
|
|
188
|
+
<main class:fullscreen class:editable {style}>
|
|
117
189
|
<div class="wrapper">
|
|
118
|
-
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
190
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
191
|
+
<div bind:this={element} class="target" onkeydown={handleKeydown}></div>
|
|
192
|
+
{#if !tiptap.v}
|
|
193
|
+
{#if preloader}
|
|
194
|
+
<Render it={preloader} />
|
|
122
195
|
{:else}
|
|
123
|
-
|
|
196
|
+
<div class="target">
|
|
197
|
+
<div>
|
|
198
|
+
{@html san(body)}
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
124
201
|
{/if}
|
|
125
202
|
{/if}
|
|
126
203
|
</div>
|
|
@@ -129,23 +206,18 @@ function selectItem(index) {
|
|
|
129
206
|
<Floating />
|
|
130
207
|
{/if}
|
|
131
208
|
{#if editable || mark}
|
|
132
|
-
<Bubble {colors} {editable} override={
|
|
133
|
-
<
|
|
134
|
-
<slot name="bubbleOverride" slot="override" />
|
|
209
|
+
<Bubble {colors} {editable} override={bubble}>
|
|
210
|
+
<Render it={bubble} />
|
|
135
211
|
</Bubble>
|
|
136
212
|
{/if}
|
|
137
213
|
</main>
|
|
138
214
|
|
|
139
|
-
|
|
140
215
|
<style>main {
|
|
141
216
|
position: relative;
|
|
142
217
|
overscroll-behavior: none;
|
|
143
|
-
--shadow: 0 1px 2px rgba(127, 127, 127, 0.07),
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
0 8px 16px rgba(127, 127, 127, 0.07),
|
|
147
|
-
0 16px 32px rgba(127, 127, 127, 0.07),
|
|
148
|
-
0 32px 64px rgba(127, 127, 127, 0.07);
|
|
218
|
+
--shadow: 0 1px 2px rgba(127, 127, 127, 0.07), 0 2px 4px rgba(127, 127, 127, 0.07),
|
|
219
|
+
0 4px 8px rgba(127, 127, 127, 0.07), 0 8px 16px rgba(127, 127, 127, 0.07),
|
|
220
|
+
0 16px 32px rgba(127, 127, 127, 0.07), 0 32px 64px rgba(127, 127, 127, 0.07);
|
|
149
221
|
}
|
|
150
222
|
main.fullscreen {
|
|
151
223
|
z-index: 999999999;
|
|
@@ -223,7 +295,8 @@ div > :global(div) :global(table) {
|
|
|
223
295
|
border: 1px solid var(--primary-light1);
|
|
224
296
|
border-radius: 12px;
|
|
225
297
|
}
|
|
226
|
-
div > :global(div) :global(
|
|
298
|
+
div > :global(div) :global(th),
|
|
299
|
+
div > :global(div) :global(td) {
|
|
227
300
|
padding: 8px;
|
|
228
301
|
border: 1px solid var(--primary-light1);
|
|
229
302
|
}
|
|
@@ -241,10 +314,10 @@ div > :global(div) :global(.iframe-wrapper) {
|
|
|
241
314
|
height: 600px;
|
|
242
315
|
border-radius: 12px;
|
|
243
316
|
}
|
|
244
|
-
div > :global(div) :global(
|
|
317
|
+
div > :global(div) :global(iframe) {
|
|
245
318
|
position: absolute;
|
|
246
319
|
top: 0;
|
|
247
320
|
left: 0;
|
|
248
321
|
width: 100%;
|
|
249
322
|
height: 100%;
|
|
250
|
-
}</style>
|
|
323
|
+
}</style>
|
|
@@ -1,32 +1,11 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
import '@seorii/prosemirror-math/style.css';
|
|
3
|
-
import type { UploadFn } from '../plugin/image/dragdrop';
|
|
4
3
|
declare const __propDef: {
|
|
5
|
-
props:
|
|
6
|
-
body?: string | undefined;
|
|
7
|
-
editable?: boolean | undefined;
|
|
8
|
-
mark?: boolean | undefined;
|
|
9
|
-
ref?: null | undefined;
|
|
10
|
-
options?: {} | undefined;
|
|
11
|
-
loaded?: boolean | undefined;
|
|
12
|
-
imageUpload?: UploadFn | undefined;
|
|
13
|
-
style?: string | undefined;
|
|
14
|
-
blocks?: any[] | undefined;
|
|
15
|
-
placeholder?: any;
|
|
16
|
-
sanitize?: any;
|
|
17
|
-
colors?: string[] | undefined;
|
|
18
|
-
bubbleOverride?: boolean | undefined;
|
|
19
|
-
};
|
|
4
|
+
props: Record<string, never>;
|
|
20
5
|
events: {
|
|
21
6
|
[evt: string]: CustomEvent<any>;
|
|
22
7
|
};
|
|
23
|
-
slots: {
|
|
24
|
-
preloader: {};
|
|
25
|
-
bubble: {};
|
|
26
|
-
bubbleOverride: {
|
|
27
|
-
slot: string;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
8
|
+
slots: {};
|
|
30
9
|
};
|
|
31
10
|
export type TipTapProps = typeof __propDef.props;
|
|
32
11
|
export type TipTapEvents = typeof __propDef.events;
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {getContext} from "svelte";
|
|
3
|
+
import {Button, IconButton, Render} from "nunui";
|
|
4
|
+
|
|
5
|
+
const editor = getContext<{ v: any }>('editor');
|
|
6
|
+
const tiptap = $derived(editor.v);
|
|
7
|
+
|
|
8
|
+
let {prop = '', attrs = '', label = '', icon = '', methodName = 'toggle' + prop.charAt(0).toUpperCase() + prop.slice(1), tooltip, handler, ...rest} = $props();
|
|
9
|
+
|
|
10
|
+
const isActive = $derived(() => {
|
|
11
|
+
return editor && prop && tiptap.isActive(prop, attrs);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function toggle() {
|
|
15
|
+
if (!tiptap) return
|
|
16
|
+
//tiptap.chain().focus().clearNodes().run()
|
|
17
|
+
if(handler) return handler()
|
|
18
|
+
setTimeout(() => tiptap.chain().focus()[methodName](attrs)?.run(), 0)
|
|
19
|
+
}
|
|
16
20
|
</script>
|
|
17
21
|
|
|
18
22
|
{#if icon}
|
|
19
|
-
<IconButton size="1.2em" {icon} active={isActive()}
|
|
23
|
+
<IconButton size="1.2em" {icon} active={isActive()} onclick={toggle} tooltip={tooltip} tabindex="0"/>
|
|
20
24
|
{:else}
|
|
21
|
-
<Button outlined={!isActive()}
|
|
25
|
+
<Button outlined={!isActive()} onclick={handler || toggle} small {...rest}>
|
|
22
26
|
{label}
|
|
23
|
-
<
|
|
27
|
+
<Render it={children} />
|
|
24
28
|
</Button>
|
|
25
29
|
{/if}
|
|
26
30
|
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
declare const __propDef: {
|
|
3
|
-
props:
|
|
4
|
-
[x: string]: any;
|
|
5
|
-
prop?: string | undefined;
|
|
6
|
-
attrs?: string | undefined;
|
|
7
|
-
label?: string | undefined;
|
|
8
|
-
icon?: string | undefined;
|
|
9
|
-
methodName?: string | undefined;
|
|
10
|
-
tooltip: any;
|
|
11
|
-
handler: any;
|
|
12
|
-
};
|
|
3
|
+
props: Record<string, never>;
|
|
13
4
|
events: {
|
|
14
5
|
[evt: string]: CustomEvent<any>;
|
|
15
6
|
};
|
|
16
|
-
slots: {
|
|
17
|
-
default: {};
|
|
18
|
-
};
|
|
7
|
+
slots: {};
|
|
19
8
|
};
|
|
20
9
|
export type ToolbarButtonProps = typeof __propDef.props;
|
|
21
10
|
export type ToolbarButtonEvents = typeof __propDef.events;
|
package/dist/tiptap/tiptap.d.ts
CHANGED