svelte-streamdown 1.0.7 → 1.0.9
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 +11 -5
- package/dist/Block.svelte +26 -10
- package/dist/Elements/Code.svelte +1 -1
- package/dist/Elements/Element.svelte +120 -37
- package/dist/Elements/FootnoteRef.svelte +113 -0
- package/dist/Elements/FootnoteRef.svelte.d.ts +7 -0
- package/dist/Elements/Image.svelte +3 -3
- package/dist/Elements/{A.svelte → Link.svelte} +3 -3
- package/dist/Elements/{A.svelte.d.ts → Link.svelte.d.ts} +3 -3
- package/dist/Elements/Math.svelte +3 -2
- package/dist/Elements/index.d.ts +5 -25
- package/dist/Elements/index.js +5 -25
- package/dist/Streamdown.d.ts +1 -1
- package/dist/Streamdown.svelte +7 -1
- package/dist/Streamdown.svelte.d.ts +6 -0
- package/dist/marked/index.d.ts +18 -5
- package/dist/marked/index.js +4 -0
- package/dist/marked/marked-alert.d.ts +2 -2
- package/dist/marked/marked-alert.js +18 -18
- package/dist/marked/marked-footnotes.d.ts +1 -0
- package/dist/marked/marked-footnotes.js +28 -8
- package/dist/marked/marked-list.d.ts +36 -0
- package/dist/marked/marked-list.js +215 -0
- package/dist/marked/marked-math.js +0 -3
- package/dist/marked/marked-subsup.d.ts +28 -0
- package/dist/marked/marked-subsup.js +44 -0
- package/dist/theme.d.ts +48 -42
- package/dist/theme.js +47 -43
- package/dist/utils/parse-incomplete-markdown.js +157 -0
- package/dist/utils/useClickOutside.svelte.d.ts +8 -0
- package/dist/utils/useClickOutside.svelte.js +42 -0
- package/dist/utils/useKeyDown.svelte.d.ts +5 -0
- package/dist/utils/useKeyDown.svelte.js +20 -0
- package/package.json +3 -1
- package/dist/Elements/Blockquote.svelte +0 -28
- package/dist/Elements/Blockquote.svelte.d.ts +0 -9
- package/dist/Elements/Del.svelte +0 -28
- package/dist/Elements/Del.svelte.d.ts +0 -9
- package/dist/Elements/Em.svelte +0 -28
- package/dist/Elements/Em.svelte.d.ts +0 -9
- package/dist/Elements/Heading.svelte +0 -25
- package/dist/Elements/Heading.svelte.d.ts +0 -9
- package/dist/Elements/Hr.svelte +0 -26
- package/dist/Elements/Hr.svelte.d.ts +0 -9
- package/dist/Elements/InlineCode.svelte +0 -28
- package/dist/Elements/InlineCode.svelte.d.ts +0 -9
- package/dist/Elements/Li.svelte +0 -28
- package/dist/Elements/Li.svelte.d.ts +0 -9
- package/dist/Elements/Ol.svelte +0 -30
- package/dist/Elements/Ol.svelte.d.ts +0 -9
- package/dist/Elements/P.svelte +0 -28
- package/dist/Elements/P.svelte.d.ts +0 -9
- package/dist/Elements/Strong.svelte +0 -28
- package/dist/Elements/Strong.svelte.d.ts +0 -9
- package/dist/Elements/Sub.svelte +0 -27
- package/dist/Elements/Sub.svelte.d.ts +0 -8
- package/dist/Elements/Sup.svelte +0 -28
- package/dist/Elements/Sup.svelte.d.ts +0 -8
- package/dist/Elements/Tbody.svelte +0 -24
- package/dist/Elements/Tbody.svelte.d.ts +0 -7
- package/dist/Elements/Td.svelte +0 -28
- package/dist/Elements/Td.svelte.d.ts +0 -9
- package/dist/Elements/Th.svelte +0 -28
- package/dist/Elements/Th.svelte.d.ts +0 -9
- package/dist/Elements/Thead.svelte +0 -27
- package/dist/Elements/Thead.svelte.d.ts +0 -9
- package/dist/Elements/Tr.svelte +0 -27
- package/dist/Elements/Tr.svelte.d.ts +0 -9
- package/dist/Elements/Ul.svelte +0 -28
- package/dist/Elements/Ul.svelte.d.ts +0 -9
- /package/dist/{hightlighter.svelte.d.ts → utils/hightlighter.svelte.d.ts} +0 -0
- /package/dist/{hightlighter.svelte.js → utils/hightlighter.svelte.js} +0 -0
package/dist/theme.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ClassValue } from 'clsx';
|
|
2
2
|
export declare const cn: (...inputs: ClassValue[]) => string;
|
|
3
3
|
export declare const theme: {
|
|
4
|
-
|
|
4
|
+
link: {
|
|
5
5
|
base: string;
|
|
6
6
|
blocked: string;
|
|
7
7
|
};
|
|
@@ -34,6 +34,7 @@ export declare const theme: {
|
|
|
34
34
|
};
|
|
35
35
|
li: {
|
|
36
36
|
base: string;
|
|
37
|
+
checkbox: string;
|
|
37
38
|
};
|
|
38
39
|
code: {
|
|
39
40
|
base: string;
|
|
@@ -44,17 +45,14 @@ export declare const theme: {
|
|
|
44
45
|
skeleton: string;
|
|
45
46
|
pre: string;
|
|
46
47
|
};
|
|
47
|
-
|
|
48
|
+
codespan: {
|
|
48
49
|
base: string;
|
|
49
50
|
};
|
|
50
|
-
|
|
51
|
+
image: {
|
|
51
52
|
base: string;
|
|
52
53
|
image: string;
|
|
53
54
|
downloadButton: string;
|
|
54
55
|
};
|
|
55
|
-
pre: {
|
|
56
|
-
base: string;
|
|
57
|
-
};
|
|
58
56
|
blockquote: {
|
|
59
57
|
base: string;
|
|
60
58
|
};
|
|
@@ -72,21 +70,18 @@ export declare const theme: {
|
|
|
72
70
|
base: string;
|
|
73
71
|
table: string;
|
|
74
72
|
};
|
|
75
|
-
|
|
73
|
+
tableRow: {
|
|
76
74
|
base: string;
|
|
77
75
|
};
|
|
78
|
-
|
|
76
|
+
tableHead: {
|
|
79
77
|
base: string;
|
|
80
78
|
};
|
|
81
|
-
|
|
79
|
+
td: {
|
|
82
80
|
base: string;
|
|
83
81
|
};
|
|
84
82
|
th: {
|
|
85
83
|
base: string;
|
|
86
84
|
};
|
|
87
|
-
td: {
|
|
88
|
-
base: string;
|
|
89
|
-
};
|
|
90
85
|
sup: {
|
|
91
86
|
base: string;
|
|
92
87
|
};
|
|
@@ -107,9 +102,10 @@ export declare const theme: {
|
|
|
107
102
|
buttons: string;
|
|
108
103
|
};
|
|
109
104
|
math: {
|
|
110
|
-
|
|
105
|
+
block: string;
|
|
106
|
+
inline: string;
|
|
111
107
|
};
|
|
112
|
-
|
|
108
|
+
br: {
|
|
113
109
|
base: string;
|
|
114
110
|
};
|
|
115
111
|
em: {
|
|
@@ -118,9 +114,15 @@ export declare const theme: {
|
|
|
118
114
|
del: {
|
|
119
115
|
base: string;
|
|
120
116
|
};
|
|
117
|
+
footnoteRef: {
|
|
118
|
+
base: string;
|
|
119
|
+
};
|
|
120
|
+
footnotePopover: {
|
|
121
|
+
base: string;
|
|
122
|
+
};
|
|
121
123
|
};
|
|
122
124
|
export declare const shadcnTheme: {
|
|
123
|
-
|
|
125
|
+
link: {
|
|
124
126
|
base: string;
|
|
125
127
|
blocked: string;
|
|
126
128
|
};
|
|
@@ -153,6 +155,7 @@ export declare const shadcnTheme: {
|
|
|
153
155
|
};
|
|
154
156
|
li: {
|
|
155
157
|
base: string;
|
|
158
|
+
checkbox: string;
|
|
156
159
|
};
|
|
157
160
|
code: {
|
|
158
161
|
base: string;
|
|
@@ -163,17 +166,14 @@ export declare const shadcnTheme: {
|
|
|
163
166
|
skeleton: string;
|
|
164
167
|
pre: string;
|
|
165
168
|
};
|
|
166
|
-
|
|
169
|
+
codespan: {
|
|
167
170
|
base: string;
|
|
168
171
|
};
|
|
169
|
-
|
|
172
|
+
image: {
|
|
170
173
|
base: string;
|
|
171
174
|
image: string;
|
|
172
175
|
downloadButton: string;
|
|
173
176
|
};
|
|
174
|
-
pre: {
|
|
175
|
-
base: string;
|
|
176
|
-
};
|
|
177
177
|
blockquote: {
|
|
178
178
|
base: string;
|
|
179
179
|
};
|
|
@@ -191,21 +191,18 @@ export declare const shadcnTheme: {
|
|
|
191
191
|
base: string;
|
|
192
192
|
table: string;
|
|
193
193
|
};
|
|
194
|
-
|
|
194
|
+
tableRow: {
|
|
195
195
|
base: string;
|
|
196
196
|
};
|
|
197
|
-
|
|
197
|
+
tableHead: {
|
|
198
198
|
base: string;
|
|
199
199
|
};
|
|
200
|
-
|
|
200
|
+
td: {
|
|
201
201
|
base: string;
|
|
202
202
|
};
|
|
203
203
|
th: {
|
|
204
204
|
base: string;
|
|
205
205
|
};
|
|
206
|
-
td: {
|
|
207
|
-
base: string;
|
|
208
|
-
};
|
|
209
206
|
sup: {
|
|
210
207
|
base: string;
|
|
211
208
|
};
|
|
@@ -226,9 +223,10 @@ export declare const shadcnTheme: {
|
|
|
226
223
|
buttons: string;
|
|
227
224
|
};
|
|
228
225
|
math: {
|
|
229
|
-
|
|
226
|
+
block: string;
|
|
227
|
+
inline: string;
|
|
230
228
|
};
|
|
231
|
-
|
|
229
|
+
br: {
|
|
232
230
|
base: string;
|
|
233
231
|
};
|
|
234
232
|
em: {
|
|
@@ -237,10 +235,16 @@ export declare const shadcnTheme: {
|
|
|
237
235
|
del: {
|
|
238
236
|
base: string;
|
|
239
237
|
};
|
|
238
|
+
footnoteRef: {
|
|
239
|
+
base: string;
|
|
240
|
+
};
|
|
241
|
+
footnotePopover: {
|
|
242
|
+
base: string;
|
|
243
|
+
};
|
|
240
244
|
};
|
|
241
245
|
export type Theme = typeof theme;
|
|
242
246
|
export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tailwind" | "shadcn") => {
|
|
243
|
-
|
|
247
|
+
link: {
|
|
244
248
|
base: string;
|
|
245
249
|
blocked: string;
|
|
246
250
|
};
|
|
@@ -273,6 +277,7 @@ export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tai
|
|
|
273
277
|
};
|
|
274
278
|
li: {
|
|
275
279
|
base: string;
|
|
280
|
+
checkbox: string;
|
|
276
281
|
};
|
|
277
282
|
code: {
|
|
278
283
|
base: string;
|
|
@@ -283,17 +288,14 @@ export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tai
|
|
|
283
288
|
skeleton: string;
|
|
284
289
|
pre: string;
|
|
285
290
|
};
|
|
286
|
-
|
|
291
|
+
codespan: {
|
|
287
292
|
base: string;
|
|
288
293
|
};
|
|
289
|
-
|
|
294
|
+
image: {
|
|
290
295
|
base: string;
|
|
291
296
|
image: string;
|
|
292
297
|
downloadButton: string;
|
|
293
298
|
};
|
|
294
|
-
pre: {
|
|
295
|
-
base: string;
|
|
296
|
-
};
|
|
297
299
|
blockquote: {
|
|
298
300
|
base: string;
|
|
299
301
|
};
|
|
@@ -311,21 +313,18 @@ export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tai
|
|
|
311
313
|
base: string;
|
|
312
314
|
table: string;
|
|
313
315
|
};
|
|
314
|
-
|
|
316
|
+
tableRow: {
|
|
315
317
|
base: string;
|
|
316
318
|
};
|
|
317
|
-
|
|
319
|
+
tableHead: {
|
|
318
320
|
base: string;
|
|
319
321
|
};
|
|
320
|
-
|
|
322
|
+
td: {
|
|
321
323
|
base: string;
|
|
322
324
|
};
|
|
323
325
|
th: {
|
|
324
326
|
base: string;
|
|
325
327
|
};
|
|
326
|
-
td: {
|
|
327
|
-
base: string;
|
|
328
|
-
};
|
|
329
328
|
sup: {
|
|
330
329
|
base: string;
|
|
331
330
|
};
|
|
@@ -346,9 +345,10 @@ export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tai
|
|
|
346
345
|
buttons: string;
|
|
347
346
|
};
|
|
348
347
|
math: {
|
|
349
|
-
|
|
348
|
+
block: string;
|
|
349
|
+
inline: string;
|
|
350
350
|
};
|
|
351
|
-
|
|
351
|
+
br: {
|
|
352
352
|
base: string;
|
|
353
353
|
};
|
|
354
354
|
em: {
|
|
@@ -357,4 +357,10 @@ export declare const mergeTheme: (customTheme?: Partial<Theme>, baseTheme?: "tai
|
|
|
357
357
|
del: {
|
|
358
358
|
base: string;
|
|
359
359
|
};
|
|
360
|
+
footnoteRef: {
|
|
361
|
+
base: string;
|
|
362
|
+
};
|
|
363
|
+
footnotePopover: {
|
|
364
|
+
base: string;
|
|
365
|
+
};
|
|
360
366
|
};
|
package/dist/theme.js
CHANGED
|
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
|
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
export const cn = (...inputs) => twMerge(clsx(inputs));
|
|
4
4
|
export const theme = {
|
|
5
|
-
|
|
5
|
+
link: {
|
|
6
6
|
base: 'text-blue-600 font-medium underline',
|
|
7
7
|
blocked: 'text-gray-500'
|
|
8
8
|
},
|
|
@@ -28,13 +28,14 @@ export const theme = {
|
|
|
28
28
|
base: ''
|
|
29
29
|
},
|
|
30
30
|
ul: {
|
|
31
|
-
base: 'ml-4 list-
|
|
31
|
+
base: 'ml-4 list-inside list-disc whitespace-normal'
|
|
32
32
|
},
|
|
33
33
|
ol: {
|
|
34
|
-
base: 'ml-4 list-
|
|
34
|
+
base: 'ml-4 list-inside whitespace-normal'
|
|
35
35
|
},
|
|
36
36
|
li: {
|
|
37
|
-
base: 'py-1'
|
|
37
|
+
base: 'py-1 marker:hidden',
|
|
38
|
+
checkbox: '-ml-2'
|
|
38
39
|
},
|
|
39
40
|
code: {
|
|
40
41
|
base: 'my-4 w-full overflow-hidden rounded-xl border border-gray-200 flex flex-col',
|
|
@@ -45,17 +46,14 @@ export const theme = {
|
|
|
45
46
|
skeleton: 'rounded-md font-mono text-transparent bg-gray-200 whitespace-nowrap inline-block',
|
|
46
47
|
pre: 'overflow-x-auto font-mono p-0 bg-gray-100/40'
|
|
47
48
|
},
|
|
48
|
-
|
|
49
|
-
base: 'bg-gray-100 rounded px-1.5 py-0.5 font-mono'
|
|
49
|
+
codespan: {
|
|
50
|
+
base: 'bg-gray-100 rounded px-1.5 py-0.5 font-mono text-[0.9em]'
|
|
50
51
|
},
|
|
51
|
-
|
|
52
|
+
image: {
|
|
52
53
|
base: 'group relative my-4 mx-auto w-fit block',
|
|
53
54
|
image: 'max-w-full rounded-lg',
|
|
54
55
|
downloadButton: 'absolute right-2 bottom-2 flex h-8 w-8 cursor-pointer items-center justify-center rounded-md border border-gray-200 bg-white/90 shadow-sm backdrop-blur-sm transition-all duration-200 hover:bg-white opacity-0 group-hover:opacity-100'
|
|
55
56
|
},
|
|
56
|
-
pre: {
|
|
57
|
-
base: 'overflow-x-auto font-mono text-xs p-4 bg-gray-100/40'
|
|
58
|
-
},
|
|
59
57
|
blockquote: {
|
|
60
58
|
base: 'border-gray-600/30 text-gray-600 my-4 border-l-4 pl-4 italic'
|
|
61
59
|
},
|
|
@@ -73,21 +71,18 @@ export const theme = {
|
|
|
73
71
|
base: 'overflow-x-auto max-w-full my-4 border border-gray-200 rounded-lg',
|
|
74
72
|
table: 'w-full border-collapse min-w-full'
|
|
75
73
|
},
|
|
76
|
-
|
|
77
|
-
base: 'bg-gray-100/80'
|
|
78
|
-
},
|
|
79
|
-
tbody: {
|
|
80
|
-
base: 'divide-gray-200 bg-gray-100/40 divide-y'
|
|
81
|
-
},
|
|
82
|
-
tr: {
|
|
74
|
+
tableRow: {
|
|
83
75
|
base: 'border-gray-200 border-b hover:bg-gray-100/50 transition-colors'
|
|
84
76
|
},
|
|
85
|
-
|
|
86
|
-
base: '
|
|
77
|
+
tableHead: {
|
|
78
|
+
base: 'bg-gray-200/80'
|
|
87
79
|
},
|
|
88
80
|
td: {
|
|
89
81
|
base: 'px-4 py-3 text-sm min-w-[200px] max-w-[400px] break-words'
|
|
90
82
|
},
|
|
83
|
+
th: {
|
|
84
|
+
base: 'text-left px-4 py-3 text-sm text-foreground min-w-[200px] max-w-[400px] break-words'
|
|
85
|
+
},
|
|
91
86
|
sup: {
|
|
92
87
|
base: 'text-sm'
|
|
93
88
|
},
|
|
@@ -108,9 +103,10 @@ export const theme = {
|
|
|
108
103
|
buttons: 'absolute right-1 top-1 z-10 flex h-fit w-fit items-center gap-1'
|
|
109
104
|
},
|
|
110
105
|
math: {
|
|
111
|
-
|
|
106
|
+
block: '',
|
|
107
|
+
inline: ''
|
|
112
108
|
},
|
|
113
|
-
|
|
109
|
+
br: {
|
|
114
110
|
base: ''
|
|
115
111
|
},
|
|
116
112
|
em: {
|
|
@@ -118,10 +114,16 @@ export const theme = {
|
|
|
118
114
|
},
|
|
119
115
|
del: {
|
|
120
116
|
base: 'line-through'
|
|
117
|
+
},
|
|
118
|
+
footnoteRef: {
|
|
119
|
+
base: 'text-gray-600 px-1 py-0.5 rounded-md bg-gray-100/80'
|
|
120
|
+
},
|
|
121
|
+
footnotePopover: {
|
|
122
|
+
base: 'fixed z-50 max-h-[30vh] max-w-3xl overflow-y-auto rounded-lg bg-background p-4 shadow'
|
|
121
123
|
}
|
|
122
124
|
};
|
|
123
125
|
export const shadcnTheme = {
|
|
124
|
-
|
|
126
|
+
link: {
|
|
125
127
|
base: 'text-primary font-medium underline hover:text-primary/80',
|
|
126
128
|
blocked: 'text-muted-foreground'
|
|
127
129
|
},
|
|
@@ -147,13 +149,14 @@ export const shadcnTheme = {
|
|
|
147
149
|
base: 'text-foreground'
|
|
148
150
|
},
|
|
149
151
|
ul: {
|
|
150
|
-
base: 'ml-4 list-
|
|
152
|
+
base: 'ml-4 list-inside list-disc whitespace-normal text-foreground'
|
|
151
153
|
},
|
|
152
154
|
ol: {
|
|
153
|
-
base: 'ml-4 list-
|
|
155
|
+
base: 'ml-4 list-inside whitespace-normal text-foreground'
|
|
154
156
|
},
|
|
155
157
|
li: {
|
|
156
|
-
base: 'py-1'
|
|
158
|
+
base: 'py-1',
|
|
159
|
+
checkbox: '-ml-2'
|
|
157
160
|
},
|
|
158
161
|
code: {
|
|
159
162
|
base: 'my-4 w-full overflow-hidden rounded-lg border border-border flex flex-col',
|
|
@@ -164,17 +167,14 @@ export const shadcnTheme = {
|
|
|
164
167
|
skeleton: 'rounded-md font-mono text-transparent bg-muted whitespace-nowrap inline-block',
|
|
165
168
|
pre: 'overflow-x-auto font-mono p-0 bg-muted/40'
|
|
166
169
|
},
|
|
167
|
-
|
|
168
|
-
base: 'bg-muted rounded px-1.5 py-0.5 font-mono text-foreground'
|
|
170
|
+
codespan: {
|
|
171
|
+
base: 'bg-muted rounded px-1.5 py-0.5 font-mono text-foreground text-[0.9em]'
|
|
169
172
|
},
|
|
170
|
-
|
|
173
|
+
image: {
|
|
171
174
|
base: 'group relative my-4 mx-auto w-fit block',
|
|
172
175
|
image: 'max-w-full rounded-lg',
|
|
173
176
|
downloadButton: 'absolute right-2 bottom-2 flex h-8 w-8 cursor-pointer items-center justify-center rounded-md border border-border bg-background/90 shadow-sm backdrop-blur-sm transition-all duration-200 hover:bg-background opacity-0 group-hover:opacity-100'
|
|
174
177
|
},
|
|
175
|
-
pre: {
|
|
176
|
-
base: 'overflow-x-auto font-mono text-xs p-4 bg-muted/40'
|
|
177
|
-
},
|
|
178
178
|
blockquote: {
|
|
179
179
|
base: 'border-muted-foreground/30 text-muted-foreground my-4 border-l-4 pl-4 italic'
|
|
180
180
|
},
|
|
@@ -192,21 +192,18 @@ export const shadcnTheme = {
|
|
|
192
192
|
base: 'overflow-x-auto max-w-full my-4 rounded-lg border border-border',
|
|
193
193
|
table: 'w-full border-collapse min-w-full'
|
|
194
194
|
},
|
|
195
|
-
|
|
196
|
-
base: 'bg-muted/50'
|
|
197
|
-
},
|
|
198
|
-
tbody: {
|
|
199
|
-
base: 'divide-border bg-card divide-y'
|
|
200
|
-
},
|
|
201
|
-
tr: {
|
|
195
|
+
tableRow: {
|
|
202
196
|
base: 'border-border border-b hover:bg-muted/50 transition-colors'
|
|
203
197
|
},
|
|
204
|
-
|
|
205
|
-
base: '
|
|
198
|
+
tableHead: {
|
|
199
|
+
base: 'bg-muted/80'
|
|
206
200
|
},
|
|
207
201
|
td: {
|
|
208
202
|
base: 'px-4 py-3 text-sm text-foreground min-w-[200px] max-w-[400px] break-words'
|
|
209
203
|
},
|
|
204
|
+
th: {
|
|
205
|
+
base: 'text-left px-4 py-3 text-sm text-foreground min-w-[200px] max-w-[400px] break-words'
|
|
206
|
+
},
|
|
210
207
|
sup: {
|
|
211
208
|
base: 'text-sm'
|
|
212
209
|
},
|
|
@@ -227,16 +224,23 @@ export const shadcnTheme = {
|
|
|
227
224
|
buttons: 'absolute right-1 top-1 z-10 flex h-fit w-fit items-center gap-1'
|
|
228
225
|
},
|
|
229
226
|
math: {
|
|
230
|
-
|
|
227
|
+
block: 'text-foreground',
|
|
228
|
+
inline: 'text-foreground'
|
|
231
229
|
},
|
|
232
|
-
|
|
233
|
-
base: '
|
|
230
|
+
br: {
|
|
231
|
+
base: ''
|
|
234
232
|
},
|
|
235
233
|
em: {
|
|
236
234
|
base: 'italic text-foreground'
|
|
237
235
|
},
|
|
238
236
|
del: {
|
|
239
237
|
base: 'line-through text-muted-foreground'
|
|
238
|
+
},
|
|
239
|
+
footnoteRef: {
|
|
240
|
+
base: 'text-muted-foreground px-1 text-sm inline-block rounded-full bg-muted/80 aspect-square border border-border'
|
|
241
|
+
},
|
|
242
|
+
footnotePopover: {
|
|
243
|
+
base: 'fixed z-50 max-h-[30vh] shadow max-w-3xl overflow-y-auto rounded-lg bg-background p-4'
|
|
240
244
|
}
|
|
241
245
|
};
|
|
242
246
|
export const mergeTheme = (customTheme, baseTheme) => {
|
|
@@ -6,6 +6,8 @@ const singleAsteriskPattern = /(\*)([^*]*?)$/;
|
|
|
6
6
|
const singleUnderscorePattern = /(_)([^_]*?)$/;
|
|
7
7
|
const inlineCodePattern = /(`)([^`]*?)$/;
|
|
8
8
|
const strikethroughPattern = /(~~)([^~]*?)$/;
|
|
9
|
+
const subPattern = /(~)([^~]*?)$/;
|
|
10
|
+
const supPattern = /(\^)([^\^]*?)$/;
|
|
9
11
|
// Helper function to check if we have a complete code block
|
|
10
12
|
const hasCompleteCodeBlock = (text) => {
|
|
11
13
|
const tripleBackticks = (text.match(/```/g) || []).length;
|
|
@@ -196,6 +198,38 @@ const isWithinMathBlock = (text, position) => {
|
|
|
196
198
|
}
|
|
197
199
|
return inInlineMath || inBlockMath;
|
|
198
200
|
};
|
|
201
|
+
// Check if a position is within a footnote reference pattern [^label]
|
|
202
|
+
const isWithinFootnoteRef = (text, position) => {
|
|
203
|
+
// Look backwards from position to find if we're inside [^...]
|
|
204
|
+
let openBracketPos = -1;
|
|
205
|
+
let caretPos = -1;
|
|
206
|
+
for (let i = position; i >= 0; i--) {
|
|
207
|
+
if (text[i] === ']') {
|
|
208
|
+
// Found closing bracket before our position, not in footnote
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
if (text[i] === '^' && caretPos === -1) {
|
|
212
|
+
caretPos = i;
|
|
213
|
+
}
|
|
214
|
+
if (text[i] === '[') {
|
|
215
|
+
openBracketPos = i;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Check if we have the pattern [^ and our position is after the caret
|
|
220
|
+
if (openBracketPos !== -1 && caretPos === openBracketPos + 1 && position >= caretPos) {
|
|
221
|
+
// Look forward to see if there's a closing bracket
|
|
222
|
+
for (let i = position + 1; i < text.length; i++) {
|
|
223
|
+
if (text[i] === ']') {
|
|
224
|
+
return true; // We're inside [^...] pattern
|
|
225
|
+
}
|
|
226
|
+
if (text[i] === '[' || text[i] === '\n') {
|
|
227
|
+
break; // Invalid pattern
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
};
|
|
199
233
|
// Counts single underscores that are not part of double underscores, not escaped, and not in math blocks
|
|
200
234
|
const countSingleUnderscores = (text) => {
|
|
201
235
|
return text.split('').reduce((acc, char, index) => {
|
|
@@ -335,6 +369,127 @@ const handleIncompleteStrikethrough = (text) => {
|
|
|
335
369
|
}
|
|
336
370
|
return text;
|
|
337
371
|
};
|
|
372
|
+
// Counts single tildes that are not part of double tildes and not escaped
|
|
373
|
+
const countSingleTildes = (text) => {
|
|
374
|
+
return text.split('').reduce((acc, char, index) => {
|
|
375
|
+
if (char === '~') {
|
|
376
|
+
const prevChar = text[index - 1];
|
|
377
|
+
const nextChar = text[index + 1];
|
|
378
|
+
// Skip if escaped with backslash
|
|
379
|
+
if (prevChar === '\\') {
|
|
380
|
+
return acc;
|
|
381
|
+
}
|
|
382
|
+
if (prevChar !== '~' && nextChar !== '~') {
|
|
383
|
+
return acc + 1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return acc;
|
|
387
|
+
}, 0);
|
|
388
|
+
};
|
|
389
|
+
// Completes incomplete subscript formatting (~)
|
|
390
|
+
const handleIncompleteSub = (text) => {
|
|
391
|
+
// Don't process if inside a complete code block
|
|
392
|
+
if (hasCompleteCodeBlock(text)) {
|
|
393
|
+
return text;
|
|
394
|
+
}
|
|
395
|
+
const singleTildes = countSingleTildes(text);
|
|
396
|
+
if (singleTildes % 2 === 1) {
|
|
397
|
+
// Find the last unmatched tilde and add content until we find a good place to close
|
|
398
|
+
const lastTildeIndex = text.lastIndexOf('~');
|
|
399
|
+
if (lastTildeIndex !== -1) {
|
|
400
|
+
// Check if the tilde is within a math block - if so, don't process
|
|
401
|
+
if (isWithinMathBlock(text, lastTildeIndex)) {
|
|
402
|
+
return text;
|
|
403
|
+
}
|
|
404
|
+
const afterTilde = text.substring(lastTildeIndex + 1);
|
|
405
|
+
// Don't close if there's no meaningful content after the opening marker
|
|
406
|
+
if (!afterTilde || /^[\s_~*`^]*$/.test(afterTilde)) {
|
|
407
|
+
return text;
|
|
408
|
+
}
|
|
409
|
+
// Find the end of the subscript content
|
|
410
|
+
// For typical sub/sup patterns, look for single numbers, letters, or simple expressions
|
|
411
|
+
const endMatch = afterTilde.match(/^([0-9]+|[a-zA-Z]|[a-zA-Z0-9]{1,3})(?=\s|[^a-zA-Z0-9]|$)/);
|
|
412
|
+
if (endMatch) {
|
|
413
|
+
const contentLength = endMatch[1].length;
|
|
414
|
+
const insertPosition = lastTildeIndex + 1 + contentLength;
|
|
415
|
+
return text.substring(0, insertPosition) + '~' + text.substring(insertPosition);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
// Fallback: if no clear boundary, treat everything until space as content
|
|
419
|
+
const spaceMatch = afterTilde.match(/^([^\s]+)/);
|
|
420
|
+
if (spaceMatch) {
|
|
421
|
+
const contentLength = spaceMatch[1].length;
|
|
422
|
+
const insertPosition = lastTildeIndex + 1 + contentLength;
|
|
423
|
+
return text.substring(0, insertPosition) + '~' + text.substring(insertPosition);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return text;
|
|
429
|
+
};
|
|
430
|
+
// Counts single carets that are not escaped and not in footnote references
|
|
431
|
+
const countSingleCarets = (text) => {
|
|
432
|
+
return text.split('').reduce((acc, char, index) => {
|
|
433
|
+
if (char === '^') {
|
|
434
|
+
const prevChar = text[index - 1];
|
|
435
|
+
// Skip if escaped with backslash
|
|
436
|
+
if (prevChar === '\\') {
|
|
437
|
+
return acc;
|
|
438
|
+
}
|
|
439
|
+
// Skip if within footnote reference
|
|
440
|
+
if (isWithinFootnoteRef(text, index)) {
|
|
441
|
+
return acc;
|
|
442
|
+
}
|
|
443
|
+
return acc + 1;
|
|
444
|
+
}
|
|
445
|
+
return acc;
|
|
446
|
+
}, 0);
|
|
447
|
+
};
|
|
448
|
+
// Completes incomplete superscript formatting (^)
|
|
449
|
+
const handleIncompleteSup = (text) => {
|
|
450
|
+
// Don't process if inside a complete code block
|
|
451
|
+
if (hasCompleteCodeBlock(text)) {
|
|
452
|
+
return text;
|
|
453
|
+
}
|
|
454
|
+
const singleCarets = countSingleCarets(text);
|
|
455
|
+
if (singleCarets % 2 === 1) {
|
|
456
|
+
// Find the last unmatched caret and add content until we find a good place to close
|
|
457
|
+
const lastCaretIndex = text.lastIndexOf('^');
|
|
458
|
+
if (lastCaretIndex !== -1) {
|
|
459
|
+
// Check if the caret is within a math block - if so, don't process
|
|
460
|
+
if (isWithinMathBlock(text, lastCaretIndex)) {
|
|
461
|
+
return text;
|
|
462
|
+
}
|
|
463
|
+
// Check if the caret is within a footnote reference - if so, don't process
|
|
464
|
+
if (isWithinFootnoteRef(text, lastCaretIndex)) {
|
|
465
|
+
return text;
|
|
466
|
+
}
|
|
467
|
+
const afterCaret = text.substring(lastCaretIndex + 1);
|
|
468
|
+
// Don't close if there's no meaningful content after the opening marker
|
|
469
|
+
if (!afterCaret || /^[\s_~*`^]*$/.test(afterCaret)) {
|
|
470
|
+
return text;
|
|
471
|
+
}
|
|
472
|
+
// Find the end of the superscript content
|
|
473
|
+
// For typical sub/sup patterns, look for single numbers, letters, or simple expressions
|
|
474
|
+
const endMatch = afterCaret.match(/^([0-9]+|[a-zA-Z]|[a-zA-Z0-9]{1,3})(?=\s|[^a-zA-Z0-9]|$)/);
|
|
475
|
+
if (endMatch) {
|
|
476
|
+
const contentLength = endMatch[1].length;
|
|
477
|
+
const insertPosition = lastCaretIndex + 1 + contentLength;
|
|
478
|
+
return text.substring(0, insertPosition) + '^' + text.substring(insertPosition);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
// Fallback: if no clear boundary, treat everything until space as content
|
|
482
|
+
const spaceMatch = afterCaret.match(/^([^\s]+)/);
|
|
483
|
+
if (spaceMatch) {
|
|
484
|
+
const contentLength = spaceMatch[1].length;
|
|
485
|
+
const insertPosition = lastCaretIndex + 1 + contentLength;
|
|
486
|
+
return text.substring(0, insertPosition) + '^' + text.substring(insertPosition);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return text;
|
|
492
|
+
};
|
|
338
493
|
// Counts single dollar signs that are not part of double dollar signs and not escaped
|
|
339
494
|
const _countSingleDollarSigns = (text) => {
|
|
340
495
|
return text.split('').reduce((acc, char, index) => {
|
|
@@ -435,6 +590,8 @@ export const parseIncompleteMarkdown = (text) => {
|
|
|
435
590
|
result = handleIncompleteSingleUnderscoreItalic(result);
|
|
436
591
|
result = handleIncompleteInlineCode(result);
|
|
437
592
|
result = handleIncompleteStrikethrough(result);
|
|
593
|
+
result = handleIncompleteSub(result);
|
|
594
|
+
result = handleIncompleteSup(result);
|
|
438
595
|
// Handle KaTeX formatting (only block math with $$)
|
|
439
596
|
result = handleIncompleteBlockKatex(result);
|
|
440
597
|
// Note: We don't handle inline KaTeX with single $ as they're likely currency symbols
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
2
|
+
import { on } from 'svelte/events';
|
|
3
|
+
export const useClickOutside = (props) => {
|
|
4
|
+
const refs = new SvelteSet();
|
|
5
|
+
let listener = null;
|
|
6
|
+
const onClickOutside = (e) => {
|
|
7
|
+
let inRef = false;
|
|
8
|
+
if (props.isActive) {
|
|
9
|
+
const path = e.composedPath();
|
|
10
|
+
path.forEach((node) => {
|
|
11
|
+
refs.forEach((ref) => {
|
|
12
|
+
if (ref instanceof Node && node instanceof Node && ref?.isSameNode(node)) {
|
|
13
|
+
inRef = true;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
if (!inRef) {
|
|
18
|
+
props.callback();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
get attachment() {
|
|
24
|
+
return props.isActive
|
|
25
|
+
? (node) => {
|
|
26
|
+
refs.add(node);
|
|
27
|
+
if (!listener) {
|
|
28
|
+
listener = on(node.ownerDocument, 'pointerdown', onClickOutside);
|
|
29
|
+
}
|
|
30
|
+
return () => {
|
|
31
|
+
refs.delete(node);
|
|
32
|
+
if (listener && refs.size === 0) {
|
|
33
|
+
listener();
|
|
34
|
+
listener = null;
|
|
35
|
+
console.log('clean up', listener);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
: null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
};
|