@aicayzer/inkkit 0.0.2 → 0.0.3
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 +3 -3
- package/dist/callouts.d.ts +24 -0
- package/dist/callouts.js +296 -0
- package/dist/clipboard.js +9 -0
- package/dist/comments.d.ts +55 -0
- package/dist/comments.js +487 -0
- package/dist/dialect.js +8 -0
- package/dist/editor.d.ts +3 -2
- package/dist/editor.js +16 -2
- package/dist/inline-highlight.d.ts +6 -0
- package/dist/inline-highlight.js +112 -0
- package/dist/literals.d.ts +2 -0
- package/dist/literals.js +31 -4
- package/dist/paste.js +1 -0
- package/dist/preserve.js +24 -4
- package/dist/reference-clipboard.js +5 -1
- package/dist/style.css +90 -0
- package/package.json +5 -1
package/dist/comments.js
ADDED
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { $node, $prose, $remark } from '@milkdown/kit/utils';
|
|
2
|
+
import { Fragment } from '@milkdown/kit/prose/model';
|
|
3
|
+
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
4
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
5
|
+
const lineEnding = (code) => code === -3 || code === -4 || code === -5;
|
|
6
|
+
const whitespace = (code) => code === 32 || code === -1 || code === -2;
|
|
7
|
+
function commentData(effects) {
|
|
8
|
+
let open = false;
|
|
9
|
+
return {
|
|
10
|
+
consume(code) {
|
|
11
|
+
if (!open) {
|
|
12
|
+
effects.enter('inkkitCommentData');
|
|
13
|
+
open = true;
|
|
14
|
+
}
|
|
15
|
+
effects.consume(code);
|
|
16
|
+
},
|
|
17
|
+
close() {
|
|
18
|
+
if (open) {
|
|
19
|
+
effects.exit('inkkitCommentData');
|
|
20
|
+
open = false;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const inlineComment = function (effects, ok, nok) {
|
|
26
|
+
const data = commentData(effects);
|
|
27
|
+
return start;
|
|
28
|
+
function start(code) {
|
|
29
|
+
effects.enter('inkkitCommentInline');
|
|
30
|
+
data.consume(code);
|
|
31
|
+
return second;
|
|
32
|
+
}
|
|
33
|
+
function second(code) {
|
|
34
|
+
if (code !== 37)
|
|
35
|
+
return nok(code);
|
|
36
|
+
data.consume(code);
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
39
|
+
function body(code) {
|
|
40
|
+
if (code === null)
|
|
41
|
+
return nok(code);
|
|
42
|
+
if (lineEnding(code)) {
|
|
43
|
+
data.close();
|
|
44
|
+
effects.enter('lineEnding');
|
|
45
|
+
effects.consume(code);
|
|
46
|
+
effects.exit('lineEnding');
|
|
47
|
+
return body;
|
|
48
|
+
}
|
|
49
|
+
data.consume(code);
|
|
50
|
+
return code === 37 ? closing : body;
|
|
51
|
+
}
|
|
52
|
+
function closing(code) {
|
|
53
|
+
if (code !== 37)
|
|
54
|
+
return body(code);
|
|
55
|
+
data.consume(code);
|
|
56
|
+
data.close();
|
|
57
|
+
effects.exit('inkkitCommentInline');
|
|
58
|
+
return ok;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// A flow construct owns blank lines and Markdown-looking text inside a block comment.
|
|
62
|
+
const blockComment = function (effects, ok, nok) {
|
|
63
|
+
const data = commentData(effects);
|
|
64
|
+
return start;
|
|
65
|
+
function start(code) {
|
|
66
|
+
effects.enter('inkkitCommentBlock');
|
|
67
|
+
data.consume(code);
|
|
68
|
+
return second;
|
|
69
|
+
}
|
|
70
|
+
function second(code) {
|
|
71
|
+
if (code !== 37)
|
|
72
|
+
return nok(code);
|
|
73
|
+
data.consume(code);
|
|
74
|
+
return openingEnd;
|
|
75
|
+
}
|
|
76
|
+
function openingEnd(code) {
|
|
77
|
+
if (whitespace(code)) {
|
|
78
|
+
data.consume(code);
|
|
79
|
+
return openingEnd;
|
|
80
|
+
}
|
|
81
|
+
if (!lineEnding(code))
|
|
82
|
+
return nok(code);
|
|
83
|
+
data.close();
|
|
84
|
+
effects.enter('lineEnding');
|
|
85
|
+
effects.consume(code);
|
|
86
|
+
effects.exit('lineEnding');
|
|
87
|
+
return lineStart;
|
|
88
|
+
}
|
|
89
|
+
function lineStart(code) {
|
|
90
|
+
if (whitespace(code)) {
|
|
91
|
+
data.consume(code);
|
|
92
|
+
return lineStart;
|
|
93
|
+
}
|
|
94
|
+
if (code === 37) {
|
|
95
|
+
data.consume(code);
|
|
96
|
+
return closingSecond;
|
|
97
|
+
}
|
|
98
|
+
return body(code);
|
|
99
|
+
}
|
|
100
|
+
function body(code) {
|
|
101
|
+
if (code === null)
|
|
102
|
+
return nok(code);
|
|
103
|
+
if (lineEnding(code)) {
|
|
104
|
+
data.close();
|
|
105
|
+
effects.enter('lineEnding');
|
|
106
|
+
effects.consume(code);
|
|
107
|
+
effects.exit('lineEnding');
|
|
108
|
+
return lineStart;
|
|
109
|
+
}
|
|
110
|
+
data.consume(code);
|
|
111
|
+
return lineEnding(code) ? lineStart : body;
|
|
112
|
+
}
|
|
113
|
+
function closingSecond(code) {
|
|
114
|
+
if (code !== 37)
|
|
115
|
+
return body(code);
|
|
116
|
+
data.consume(code);
|
|
117
|
+
return closingEnd;
|
|
118
|
+
}
|
|
119
|
+
function closingEnd(code) {
|
|
120
|
+
if (whitespace(code)) {
|
|
121
|
+
data.consume(code);
|
|
122
|
+
return closingEnd;
|
|
123
|
+
}
|
|
124
|
+
if (code !== null && !lineEnding(code))
|
|
125
|
+
return body(code);
|
|
126
|
+
data.close();
|
|
127
|
+
effects.exit('inkkitCommentBlock');
|
|
128
|
+
return ok(code);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const syntax = {
|
|
132
|
+
text: { 37: { name: 'inkkitCommentInline', tokenize: inlineComment } },
|
|
133
|
+
flow: {
|
|
134
|
+
37: { name: 'inkkitCommentBlock', tokenize: blockComment, concrete: true },
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
const from = {
|
|
138
|
+
enter: {
|
|
139
|
+
inkkitCommentInline(token) {
|
|
140
|
+
this.enter({ type: 'inkkitCommentInline', syntax: 'obsidian', value: '' }, token);
|
|
141
|
+
},
|
|
142
|
+
inkkitCommentBlock(token) {
|
|
143
|
+
this.enter({ type: 'inkkitCommentBlock', syntax: 'obsidian', value: '' }, token);
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
exit: {
|
|
147
|
+
inkkitCommentInline(token) {
|
|
148
|
+
const node = this.stack.at(-1);
|
|
149
|
+
node.value = this.sliceSerialize(token).slice(2, -2);
|
|
150
|
+
this.exit(token);
|
|
151
|
+
},
|
|
152
|
+
inkkitCommentBlock(token) {
|
|
153
|
+
const node = this.stack.at(-1);
|
|
154
|
+
node.value = this.sliceSerialize(token)
|
|
155
|
+
.replace(/^%%[^\S\r\n]*\r?\n/, '')
|
|
156
|
+
.replace(/(?:\r?\n)?[^\S\r\n]*%%[^\S\r\n]*$/, '');
|
|
157
|
+
this.exit(token);
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
export function commentSource(node) {
|
|
162
|
+
const body = node.textContent;
|
|
163
|
+
return node.attrs.syntax === 'html'
|
|
164
|
+
? `<!--${body}-->`
|
|
165
|
+
: node.type.name === 'comment_block' || node.attrs.block
|
|
166
|
+
? `%%\n${body}\n%%`
|
|
167
|
+
: `%%${body}%%`;
|
|
168
|
+
}
|
|
169
|
+
const handler = (node) => {
|
|
170
|
+
const comment = node;
|
|
171
|
+
const value = comment.value ?? '';
|
|
172
|
+
return comment.syntax === 'html'
|
|
173
|
+
? `<!--${value}-->`
|
|
174
|
+
: comment.type === 'inkkitCommentBlock' || comment.block
|
|
175
|
+
? `%%\n${value}\n%%`
|
|
176
|
+
: `%%${value}%%`;
|
|
177
|
+
};
|
|
178
|
+
function htmlSpans(value) {
|
|
179
|
+
const spans = [];
|
|
180
|
+
let inTag = false;
|
|
181
|
+
let quote = '';
|
|
182
|
+
for (let index = 0; index < value.length; index++) {
|
|
183
|
+
const character = value[index];
|
|
184
|
+
if (quote) {
|
|
185
|
+
if (character === quote)
|
|
186
|
+
quote = '';
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (inTag && (character === '"' || character === "'")) {
|
|
190
|
+
quote = character;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (value.startsWith('<!--', index)) {
|
|
194
|
+
const end = value.indexOf('-->', index + 4);
|
|
195
|
+
if (end < 0)
|
|
196
|
+
break;
|
|
197
|
+
spans.push({
|
|
198
|
+
start: index,
|
|
199
|
+
end: end + 3,
|
|
200
|
+
syntax: 'html',
|
|
201
|
+
value: value.slice(index + 4, end),
|
|
202
|
+
});
|
|
203
|
+
index = end + 2;
|
|
204
|
+
inTag = false;
|
|
205
|
+
}
|
|
206
|
+
else if (character === '<')
|
|
207
|
+
inTag = true;
|
|
208
|
+
else if (character === '>')
|
|
209
|
+
inTag = false;
|
|
210
|
+
}
|
|
211
|
+
return spans;
|
|
212
|
+
}
|
|
213
|
+
// Parse preserved source again rather than hiding delimiter-looking strings in code or escapes.
|
|
214
|
+
export function literalCommentSpans(value) {
|
|
215
|
+
const tree = fromMarkdown(value, {
|
|
216
|
+
extensions: [syntax],
|
|
217
|
+
mdastExtensions: [from],
|
|
218
|
+
});
|
|
219
|
+
const spans = [];
|
|
220
|
+
const visit = (node) => {
|
|
221
|
+
const start = node.position?.start.offset;
|
|
222
|
+
const end = node.position?.end.offset;
|
|
223
|
+
if (start != null && end != null) {
|
|
224
|
+
if (node.type === 'inkkitCommentInline' ||
|
|
225
|
+
node.type === 'inkkitCommentBlock')
|
|
226
|
+
spans.push({
|
|
227
|
+
start,
|
|
228
|
+
end,
|
|
229
|
+
syntax: node.syntax,
|
|
230
|
+
value: node.value,
|
|
231
|
+
block: node.type === 'inkkitCommentBlock',
|
|
232
|
+
});
|
|
233
|
+
else if (node.type === 'html')
|
|
234
|
+
spans.push(...htmlSpans(value.slice(start, end)).map((span) => ({
|
|
235
|
+
...span,
|
|
236
|
+
start: start + span.start,
|
|
237
|
+
end: start + span.end,
|
|
238
|
+
})));
|
|
239
|
+
}
|
|
240
|
+
if ('children' in node)
|
|
241
|
+
node.children.forEach(visit);
|
|
242
|
+
};
|
|
243
|
+
visit(tree);
|
|
244
|
+
return spans.sort((left, right) => left.start - right.start);
|
|
245
|
+
}
|
|
246
|
+
function remarkComments() {
|
|
247
|
+
const data = this.data();
|
|
248
|
+
(data.micromarkExtensions ??= []).push(syntax);
|
|
249
|
+
(data.fromMarkdownExtensions ??= []).push(from);
|
|
250
|
+
(data.toMarkdownExtensions ??= []).push({
|
|
251
|
+
handlers: { inkkitCommentInline: handler, inkkitCommentBlock: handler },
|
|
252
|
+
unsafe: [{ character: '%', inConstruct: 'phrasing', after: '%' }],
|
|
253
|
+
});
|
|
254
|
+
return (tree) => {
|
|
255
|
+
const visit = (node, inline, parentType) => {
|
|
256
|
+
if (parentType === 'listItem' && node.type === 'inkkitCommentBlock')
|
|
257
|
+
return {
|
|
258
|
+
type: 'paragraph',
|
|
259
|
+
children: [{ ...node, type: 'inkkitCommentInline', block: true }],
|
|
260
|
+
position: node.position,
|
|
261
|
+
};
|
|
262
|
+
if (node.type === 'html') {
|
|
263
|
+
const spans = htmlSpans(node.value);
|
|
264
|
+
if (spans.length === 1 &&
|
|
265
|
+
spans[0].start === 0 &&
|
|
266
|
+
spans[0].end === node.value.length)
|
|
267
|
+
return parentType === 'listItem'
|
|
268
|
+
? {
|
|
269
|
+
type: 'paragraph',
|
|
270
|
+
children: [
|
|
271
|
+
{
|
|
272
|
+
type: 'inkkitCommentInline',
|
|
273
|
+
syntax: 'html',
|
|
274
|
+
value: spans[0].value,
|
|
275
|
+
position: node.position,
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
position: node.position,
|
|
279
|
+
}
|
|
280
|
+
: {
|
|
281
|
+
type: inline ? 'inkkitCommentInline' : 'inkkitCommentBlock',
|
|
282
|
+
syntax: 'html',
|
|
283
|
+
value: spans[0].value,
|
|
284
|
+
position: node.position,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if ('children' in node)
|
|
288
|
+
node.children = node.children.map((child) => visit(child, node.type === 'paragraph' ||
|
|
289
|
+
node.type === 'heading' ||
|
|
290
|
+
node.type === 'tableCell' ||
|
|
291
|
+
node.type === 'link' ||
|
|
292
|
+
node.type === 'linkReference' ||
|
|
293
|
+
inline, node.type));
|
|
294
|
+
if (node.type === 'paragraph' &&
|
|
295
|
+
parentType !== 'listItem' &&
|
|
296
|
+
node.children.length === 1 &&
|
|
297
|
+
node.children[0]?.type === 'inkkitCommentInline')
|
|
298
|
+
return {
|
|
299
|
+
...node.children[0],
|
|
300
|
+
type: 'inkkitCommentBlock',
|
|
301
|
+
position: node.position,
|
|
302
|
+
};
|
|
303
|
+
return node;
|
|
304
|
+
};
|
|
305
|
+
tree.children = tree.children.map((node) => visit(node, false));
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
export const remarkCommentsPlugin = $remark('remarkComments', () => remarkComments);
|
|
309
|
+
function commentNode(inline) {
|
|
310
|
+
const name = inline ? 'comment_inline' : 'comment_block';
|
|
311
|
+
const mdastType = inline ? 'inkkitCommentInline' : 'inkkitCommentBlock';
|
|
312
|
+
return $node(name, () => ({
|
|
313
|
+
inline,
|
|
314
|
+
group: inline ? 'inline' : 'block',
|
|
315
|
+
content: 'text*',
|
|
316
|
+
marks: '',
|
|
317
|
+
code: true,
|
|
318
|
+
defining: true,
|
|
319
|
+
attrs: { syntax: { default: 'html' }, block: { default: !inline } },
|
|
320
|
+
parseDOM: [
|
|
321
|
+
{
|
|
322
|
+
tag: `${inline ? 'span' : 'div'}[data-inkkit-comment]`,
|
|
323
|
+
preserveWhitespace: 'full',
|
|
324
|
+
getAttrs: (dom) => ({
|
|
325
|
+
syntax: dom.getAttribute('data-inkkit-comment') === 'obsidian'
|
|
326
|
+
? 'obsidian'
|
|
327
|
+
: 'html',
|
|
328
|
+
}),
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
toDOM: (node) => [
|
|
332
|
+
inline ? 'span' : 'div',
|
|
333
|
+
{
|
|
334
|
+
class: `inkkit-comment inkkit-comment-${inline ? 'inline' : 'block'}`,
|
|
335
|
+
'data-inkkit-comment': node.attrs.syntax,
|
|
336
|
+
'aria-label': 'Author comment',
|
|
337
|
+
},
|
|
338
|
+
0,
|
|
339
|
+
],
|
|
340
|
+
parseMarkdown: {
|
|
341
|
+
match: (node) => node.type === mdastType,
|
|
342
|
+
runner: (state, node, type) => {
|
|
343
|
+
state.openNode(type, {
|
|
344
|
+
syntax: node.syntax,
|
|
345
|
+
block: inline ? Boolean(node.block) : true,
|
|
346
|
+
});
|
|
347
|
+
if (node.value)
|
|
348
|
+
state.addText(String(node.value));
|
|
349
|
+
state.closeNode();
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
toMarkdown: {
|
|
353
|
+
match: (node) => node.type.name === name,
|
|
354
|
+
runner: (state, node) => {
|
|
355
|
+
state.addNode(mdastType, undefined, node.textContent, {
|
|
356
|
+
syntax: node.attrs.syntax,
|
|
357
|
+
block: node.attrs.block,
|
|
358
|
+
});
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
}));
|
|
362
|
+
}
|
|
363
|
+
export const commentInline = commentNode(true);
|
|
364
|
+
export const commentBlock = commentNode(false);
|
|
365
|
+
const visibilityKey = new PluginKey('inkkit-comments-visible');
|
|
366
|
+
export const commentVisibility = $prose(() => new Plugin({
|
|
367
|
+
key: visibilityKey,
|
|
368
|
+
state: {
|
|
369
|
+
init: () => false,
|
|
370
|
+
apply: (transaction, value) => transaction.getMeta(visibilityKey) ?? value,
|
|
371
|
+
},
|
|
372
|
+
view(view) {
|
|
373
|
+
const update = () => view.dom.setAttribute('data-inkkit-comments-visible', String(visibilityKey.getState(view.state) ?? false));
|
|
374
|
+
update();
|
|
375
|
+
return { update };
|
|
376
|
+
},
|
|
377
|
+
}));
|
|
378
|
+
export function setCommentVisibility(view, visible) {
|
|
379
|
+
if (visibilityKey.getState(view.state) === visible)
|
|
380
|
+
return;
|
|
381
|
+
view.dispatch(view.state.tr
|
|
382
|
+
.setMeta(visibilityKey, visible)
|
|
383
|
+
.setMeta('addToHistory', false));
|
|
384
|
+
}
|
|
385
|
+
export const comments = [commentInline, commentBlock, commentVisibility].flat();
|
|
386
|
+
export function isComment(node) {
|
|
387
|
+
return (node.type.name === 'comment_inline' || node.type.name === 'comment_block');
|
|
388
|
+
}
|
|
389
|
+
// Authored reference metadata can retain comments after their visible nodes are removed.
|
|
390
|
+
function commentProvenance(value) {
|
|
391
|
+
if (typeof value !== 'string')
|
|
392
|
+
return false;
|
|
393
|
+
const visit = (value) => {
|
|
394
|
+
if (Array.isArray(value))
|
|
395
|
+
return value.some(visit);
|
|
396
|
+
if (!value || typeof value !== 'object')
|
|
397
|
+
return false;
|
|
398
|
+
const node = value;
|
|
399
|
+
return (node.type === 'inkkitCommentInline' ||
|
|
400
|
+
node.type === 'inkkitCommentBlock' ||
|
|
401
|
+
(node.type === 'html' &&
|
|
402
|
+
typeof node.value === 'string' &&
|
|
403
|
+
htmlSpans(node.value).length > 0) ||
|
|
404
|
+
Boolean(node.children?.some(visit)));
|
|
405
|
+
};
|
|
406
|
+
try {
|
|
407
|
+
return visit(JSON.parse(value));
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
export function shareableFragment(content) {
|
|
414
|
+
const filtered = [];
|
|
415
|
+
const labelHasComments = (label) => typeof label === 'string' &&
|
|
416
|
+
(label.includes('%%') || label.includes('<!--')) &&
|
|
417
|
+
literalCommentSpans(label).length > 0;
|
|
418
|
+
content.forEach((node) => {
|
|
419
|
+
if (isComment(node))
|
|
420
|
+
return;
|
|
421
|
+
if (node.type.name === 'reference_definition' &&
|
|
422
|
+
labelHasComments(node.attrs.label))
|
|
423
|
+
return;
|
|
424
|
+
node = node.mark(node.marks.map((mark) => {
|
|
425
|
+
if (mark.type.name !== 'link')
|
|
426
|
+
return mark;
|
|
427
|
+
const clearTarget = labelHasComments(mark.attrs.label);
|
|
428
|
+
if (!clearTarget && !commentProvenance(mark.attrs.referenceContent))
|
|
429
|
+
return mark;
|
|
430
|
+
return mark.type.create({
|
|
431
|
+
...mark.attrs,
|
|
432
|
+
referenceContent: null,
|
|
433
|
+
...(clearTarget
|
|
434
|
+
? { identifier: null, label: null, referenceType: null }
|
|
435
|
+
: {}),
|
|
436
|
+
});
|
|
437
|
+
}));
|
|
438
|
+
if (!node.childCount) {
|
|
439
|
+
filtered.push(node);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const inner = shareableFragment(node.content);
|
|
443
|
+
let whitespaceOnly = true, removedComment = false;
|
|
444
|
+
inner.forEach((child) => {
|
|
445
|
+
if (!(child.isText && !child.text.trim()) &&
|
|
446
|
+
child.type.name !== 'hardbreak')
|
|
447
|
+
whitespaceOnly = false;
|
|
448
|
+
});
|
|
449
|
+
node.content.descendants((child) => {
|
|
450
|
+
if (isComment(child)) {
|
|
451
|
+
removedComment = true;
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
const commentOnly = removedComment && whitespaceOnly;
|
|
456
|
+
const paragraph = () => Fragment.from(node.type.schema.nodes.paragraph.create());
|
|
457
|
+
if ((inner.size === 0 || commentOnly) && node.content.size > 0) {
|
|
458
|
+
if ([
|
|
459
|
+
'footnote_definition',
|
|
460
|
+
'list_item',
|
|
461
|
+
'table_cell',
|
|
462
|
+
'table_header',
|
|
463
|
+
'inkkit_callout',
|
|
464
|
+
].includes(node.type.name))
|
|
465
|
+
filtered.push(node.copy(paragraph()));
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (!node.type.validContent(inner)) {
|
|
469
|
+
if (node.type.name === 'list_item')
|
|
470
|
+
filtered.push(node.copy(paragraph().append(inner)));
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
filtered.push(node.copy(inner));
|
|
474
|
+
});
|
|
475
|
+
return Fragment.fromArray(filtered);
|
|
476
|
+
}
|
|
477
|
+
// ProseMirror omits a parent wrapper when a selection is wholly inside its text.
|
|
478
|
+
export function commentSelectionContent(doc, from, to, content) {
|
|
479
|
+
const start = doc.resolve(from);
|
|
480
|
+
const end = doc.resolve(to);
|
|
481
|
+
for (let depth = start.depth; depth > 0; depth--) {
|
|
482
|
+
const node = start.node(depth);
|
|
483
|
+
if (isComment(node) && end.depth >= depth && node === end.node(depth))
|
|
484
|
+
return Fragment.from(node.copy(node.content.cut(from - start.start(depth), to - start.start(depth))));
|
|
485
|
+
}
|
|
486
|
+
return content;
|
|
487
|
+
}
|
package/dist/dialect.js
CHANGED
|
@@ -5,6 +5,9 @@ import { $remark } from '@milkdown/kit/utils';
|
|
|
5
5
|
import { autolinkInputRule } from './autolink.js';
|
|
6
6
|
import { literalBlock, createLiteralPreservation } from './literals.js';
|
|
7
7
|
import { references, remarkReferencesPlugin } from './references.js';
|
|
8
|
+
import { callouts, remarkCalloutsPlugin } from './callouts.js';
|
|
9
|
+
import { inlineHighlight } from './inline-highlight.js';
|
|
10
|
+
import { comments, remarkCommentsPlugin } from './comments.js';
|
|
8
11
|
import { gfmTableFromMarkdown, gfmTableToMarkdown } from 'mdast-util-gfm-table';
|
|
9
12
|
import { gfmTable } from 'micromark-extension-gfm-table';
|
|
10
13
|
import { defaultHandlers, } from 'mdast-util-to-markdown';
|
|
@@ -252,10 +255,15 @@ export const tables = [
|
|
|
252
255
|
export function createDialect(images) {
|
|
253
256
|
return [
|
|
254
257
|
remarkReferencesPlugin,
|
|
258
|
+
remarkCalloutsPlugin,
|
|
259
|
+
remarkCommentsPlugin,
|
|
255
260
|
// Protect unsupported inline HTML before the empty-line plugin consumes break nodes.
|
|
256
261
|
createLiteralPreservation(images),
|
|
257
262
|
commonmarkWithLiteralReferences,
|
|
258
263
|
references,
|
|
264
|
+
callouts,
|
|
265
|
+
comments,
|
|
266
|
+
inlineHighlight,
|
|
259
267
|
preserveSpacerParagraphs,
|
|
260
268
|
visibleSoftbreaks,
|
|
261
269
|
normalizedImages,
|
package/dist/editor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type TableCommand } from './tables.js';
|
|
2
2
|
import { type DocumentInput, type DocumentSnapshot, type ImageAdapter, type ClipboardInput, type ClipboardOutput } from './types.js';
|
|
3
|
-
export type Mark = 'bold' | 'italic' | 'strikethrough' | 'code' | 'link';
|
|
3
|
+
export type Mark = 'bold' | 'italic' | 'strikethrough' | 'highlight' | 'code' | 'link';
|
|
4
4
|
export type Block = {
|
|
5
5
|
type: 'paragraph';
|
|
6
6
|
} | {
|
|
@@ -21,7 +21,7 @@ export interface CaretState {
|
|
|
21
21
|
/** One quote holds the whole selection; the block is what sits inside it. */
|
|
22
22
|
quoted: boolean;
|
|
23
23
|
}
|
|
24
|
-
export type FormatCommand = 'heading' | 'paragraph' | 'bold' | 'italic' | 'strikethrough' | 'code' | 'codeBlock' | 'quote' | 'bulletList' | 'orderedList' | 'taskList' | 'link';
|
|
24
|
+
export type FormatCommand = 'heading' | 'paragraph' | 'bold' | 'italic' | 'strikethrough' | 'highlight' | 'code' | 'codeBlock' | 'quote' | 'bulletList' | 'orderedList' | 'taskList' | 'link';
|
|
25
25
|
/** The bindings the app sets, by shortcut name; each runs a format command. */
|
|
26
26
|
export type Keymap = Record<string, string[]>;
|
|
27
27
|
export interface EditorEvents {
|
|
@@ -67,6 +67,7 @@ export declare class InkKitEditor {
|
|
|
67
67
|
snapshot(expectedGeneration?: number): DocumentSnapshot;
|
|
68
68
|
clipboardSnapshot(all?: boolean): Promise<ClipboardOutput>;
|
|
69
69
|
paste(input: ClipboardInput): Promise<void>;
|
|
70
|
+
setCommentsVisible(visible: boolean): void;
|
|
70
71
|
pasteAsPlainText(text: string): void;
|
|
71
72
|
table(command: TableCommand, options?: {
|
|
72
73
|
rows?: number;
|
package/dist/editor.js
CHANGED
|
@@ -20,6 +20,8 @@ import { imageView } from './images.js';
|
|
|
20
20
|
import { tablePlugins, tableCommand } from './tables.js';
|
|
21
21
|
import { InkKitError, } from './types.js';
|
|
22
22
|
import { highlightPlugin } from './highlight.js';
|
|
23
|
+
import { highlightKeymap, toggleHighlightCommand } from './inline-highlight.js';
|
|
24
|
+
import { commentSelectionContent, setCommentVisibility } from './comments.js';
|
|
23
25
|
import { PasteController } from './paste.js';
|
|
24
26
|
import { selectionPlugin } from './selection.js';
|
|
25
27
|
import { search, SearchQuery, getSearchState, setSearchState, } from 'prosemirror-search';
|
|
@@ -32,6 +34,7 @@ const shortcutCommands = {
|
|
|
32
34
|
bold: ['bold'],
|
|
33
35
|
italic: ['italic'],
|
|
34
36
|
strikethrough: ['strikethrough'],
|
|
37
|
+
highlight: ['highlight'],
|
|
35
38
|
code: ['code'],
|
|
36
39
|
codeBlock: ['codeBlock'],
|
|
37
40
|
quote: ['quote'],
|
|
@@ -43,6 +46,7 @@ const markNames = {
|
|
|
43
46
|
strong: 'bold',
|
|
44
47
|
emphasis: 'italic',
|
|
45
48
|
strike_through: 'strikethrough',
|
|
49
|
+
highlight: 'highlight',
|
|
46
50
|
inlineCode: 'code',
|
|
47
51
|
link: 'link',
|
|
48
52
|
};
|
|
@@ -341,7 +345,9 @@ export class InkKitEditor {
|
|
|
341
345
|
return { text, html: pre.outerHTML, markdown: text, images: [] };
|
|
342
346
|
}
|
|
343
347
|
const { doc, schema, selection } = this.editor.ctx.get(editorViewCtx).state;
|
|
344
|
-
const content = all
|
|
348
|
+
const content = all
|
|
349
|
+
? doc.content
|
|
350
|
+
: commentSelectionContent(doc, selection.from, selection.to, selection.content().content);
|
|
345
351
|
const valid = content.firstChild?.isInline
|
|
346
352
|
? Fragment.from(schema.nodes.paragraph.create(null, content))
|
|
347
353
|
: content;
|
|
@@ -375,6 +381,10 @@ export class InkKitEditor {
|
|
|
375
381
|
}
|
|
376
382
|
await this.pasteController.paste(input);
|
|
377
383
|
}
|
|
384
|
+
setCommentsVisible(visible) {
|
|
385
|
+
this.assertAlive();
|
|
386
|
+
setCommentVisibility(this.editor.ctx.get(editorViewCtx), visible);
|
|
387
|
+
}
|
|
378
388
|
pasteAsPlainText(text) {
|
|
379
389
|
this.assertCurrent();
|
|
380
390
|
if (this.formatType === 'txt') {
|
|
@@ -485,6 +495,7 @@ export class InkKitEditor {
|
|
|
485
495
|
unbind(emphasisKeymap);
|
|
486
496
|
unbind(inlineCodeKeymap);
|
|
487
497
|
unbind(strikethroughKeymap);
|
|
498
|
+
unbind(highlightKeymap);
|
|
488
499
|
unbind(headingKeymap, ['DowngradeHeading']);
|
|
489
500
|
unbind(paragraphKeymap);
|
|
490
501
|
unbind(blockquoteKeymap);
|
|
@@ -580,7 +591,7 @@ export class InkKitEditor {
|
|
|
580
591
|
if (instance.formatType === 'txt')
|
|
581
592
|
return;
|
|
582
593
|
const view = instance.editor.ctx.get(editorViewCtx);
|
|
583
|
-
const fragment = view.state.selection.content().content;
|
|
594
|
+
const fragment = commentSelectionContent(view.state.doc, view.state.selection.from, view.state.selection.to, view.state.selection.content().content);
|
|
584
595
|
const expanded = selectionContent(view.state.doc, fragment);
|
|
585
596
|
let hasImages = false;
|
|
586
597
|
expanded.descendants((node) => {
|
|
@@ -1011,6 +1022,9 @@ export class InkKitEditor {
|
|
|
1011
1022
|
case 'strikethrough':
|
|
1012
1023
|
run(toggleStrikethroughCommand.key);
|
|
1013
1024
|
break;
|
|
1025
|
+
case 'highlight':
|
|
1026
|
+
run(toggleHighlightCommand.key);
|
|
1027
|
+
break;
|
|
1014
1028
|
case 'code':
|
|
1015
1029
|
this.toggleInlineCode();
|
|
1016
1030
|
break;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const remarkInlineHighlightPlugin: import("@milkdown/kit/utils").$Remark<"inkkitInlineHighlight", unknown>;
|
|
2
|
+
export declare const highlightSchema: import("@milkdown/kit/utils").$MarkSchema<"highlight">;
|
|
3
|
+
export declare const toggleHighlightCommand: import("@milkdown/kit/utils").$Command<unknown>;
|
|
4
|
+
export declare const highlightInputRule: import("@milkdown/kit/utils").$InputRule;
|
|
5
|
+
export declare const highlightKeymap: import("@milkdown/kit/utils").$UserKeymap<"highlightKeymap", "ToggleHighlight">;
|
|
6
|
+
export declare const inlineHighlight: (import("@milkdown/kit/utils").$Command<unknown> | import("@milkdown/kit/utils").$Ctx<unknown, "inkkitInlineHighlight"> | import("@milkdown/kit/utils").$Ctx<import("@milkdown/kit/utils").GetMarkSchema, "highlight"> | import("@milkdown/kit/utils").$Ctx<import("@milkdown/kit/utils").KeymapConfig<"ToggleHighlight">, "highlightKeymapKeymap"> | import("@milkdown/kit/utils").$InputRule | import("@milkdown/kit/utils").$Mark | import("@milkdown/kit/utils").$Shortcut | import("@milkdown/kit/ctx").MilkdownPlugin)[];
|