@aicayzer/inkkit 0.0.1 → 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 +4 -2
- package/dist/callouts.d.ts +24 -0
- package/dist/callouts.js +296 -0
- package/dist/clipboard.js +31 -1
- package/dist/comments.d.ts +55 -0
- package/dist/comments.js +487 -0
- package/dist/dialect.js +12 -2
- package/dist/editor.d.ts +7 -2
- package/dist/editor.js +199 -10
- package/dist/inline-highlight.d.ts +6 -0
- package/dist/inline-highlight.js +112 -0
- package/dist/literals.d.ts +5 -0
- package/dist/literals.js +62 -20
- package/dist/paste.js +61 -5
- package/dist/preserve.js +254 -8
- package/dist/reference-clipboard.d.ts +8 -0
- package/dist/reference-clipboard.js +201 -0
- package/dist/references.d.ts +14 -0
- package/dist/references.js +367 -0
- package/dist/style.css +117 -0
- package/dist/types.d.ts +1 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -33,8 +33,10 @@ editor.loadDocument({
|
|
|
33
33
|
const snapshot = editor.snapshot(1)
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Markdown includes CommonMark, task lists, strikethrough, autolinks and
|
|
36
|
+
Markdown includes CommonMark, task lists, strikethrough, autolinks, GFM tables, editable footnotes and reference-style links, bounded callouts, highlights and author comments. Unsupported constructs remain literal Markdown. TXT mode treats all text literally. Images require a host adapter. RTF files remain outside the package scope.
|
|
37
37
|
|
|
38
|
-
See [the host API](docs/api.md), [preservation and clipboard behavior](docs/preservation.md), [development](docs/development.md), and [releases](docs/releasing.md).
|
|
38
|
+
See [supported syntax](docs/supported-syntax.md), [the host API](docs/api.md), [preservation and clipboard behavior](docs/preservation.md), [development](docs/development.md), and [releases](docs/releasing.md).
|
|
39
|
+
|
|
40
|
+
Planned work and release scope are tracked in the [InkKit Project](https://github.com/users/aicayzer/projects/3) and [milestones](https://github.com/aicayzer/inkkit/milestones). Release 0.0.2 is published and verified; 0.0.3 delivery is authorised. Targets from 0.0.4 remain provisional.
|
|
39
41
|
|
|
40
42
|
MIT licensed. InkKit builds on the public PadPad and Memos editors; see [NOTICE](NOTICE).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Parent, RootContent } from 'mdast';
|
|
2
|
+
interface Callout extends Parent {
|
|
3
|
+
type: 'inkkitCallout';
|
|
4
|
+
kind: string;
|
|
5
|
+
marker: string;
|
|
6
|
+
fold: string;
|
|
7
|
+
title: string;
|
|
8
|
+
titleSource: string;
|
|
9
|
+
listPlaceholder: boolean;
|
|
10
|
+
children: RootContent[];
|
|
11
|
+
}
|
|
12
|
+
declare module 'mdast' {
|
|
13
|
+
interface BlockContentMap {
|
|
14
|
+
inkkitCallout: Callout;
|
|
15
|
+
}
|
|
16
|
+
interface RootContentMap {
|
|
17
|
+
inkkitCallout: Callout;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export declare const remarkCalloutsPlugin: import("@milkdown/kit/utils").$Remark<"inkkitCallouts", unknown>;
|
|
21
|
+
export declare const calloutSchema: import("@milkdown/kit/utils").$Node;
|
|
22
|
+
export declare const calloutView: import("@milkdown/kit/utils").$Prose;
|
|
23
|
+
export declare const callouts: (import("@milkdown/kit/utils").$Node | import("@milkdown/kit/utils").$Prose)[];
|
|
24
|
+
export {};
|
package/dist/callouts.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { $node, $prose, $remark } from '@milkdown/kit/utils';
|
|
2
|
+
import { remarkCtx } from '@milkdown/kit/core';
|
|
3
|
+
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
4
|
+
import { defaultHandlers } from 'mdast-util-to-markdown';
|
|
5
|
+
const kinds = new Set(['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION']);
|
|
6
|
+
function plainHeader(processor, source) {
|
|
7
|
+
const node = processor.parse(source).children[0];
|
|
8
|
+
return node?.type === 'paragraph' &&
|
|
9
|
+
node.children.length === 1 &&
|
|
10
|
+
node.children[0]?.type === 'text'
|
|
11
|
+
? node.children[0].value
|
|
12
|
+
: undefined;
|
|
13
|
+
}
|
|
14
|
+
const calloutHandler = (untyped, parent, state, info) => {
|
|
15
|
+
const node = untyped;
|
|
16
|
+
const body = defaultHandlers.blockquote({ type: 'blockquote', children: node.children }, parent, state, info);
|
|
17
|
+
const title = node.titleSource ?? node.title;
|
|
18
|
+
return `> ${node.marker}${node.fold}${title ? ` ${title}` : ''}\n${body}`;
|
|
19
|
+
};
|
|
20
|
+
function remarkCallouts() {
|
|
21
|
+
const processor = this;
|
|
22
|
+
const data = this.data();
|
|
23
|
+
(data.toMarkdownExtensions ??= []).push({
|
|
24
|
+
handlers: { inkkitCallout: calloutHandler },
|
|
25
|
+
});
|
|
26
|
+
return (tree, file) => {
|
|
27
|
+
const source = String(file.value).replace(/^\uFEFF/, '');
|
|
28
|
+
const visit = (node, parent, index) => {
|
|
29
|
+
if (node.type === 'blockquote') {
|
|
30
|
+
const start = node.position?.start.offset, end = node.position?.end.offset;
|
|
31
|
+
const raw = start == null || end == null ? '' : source.slice(start, end);
|
|
32
|
+
const header = /^>[ \t]*([\s\S]*?)(?:\r?\n|$)/.exec(raw)?.[1] ?? '';
|
|
33
|
+
if (header.startsWith('[!')) {
|
|
34
|
+
const match = /^(\[!([A-Za-z]+)\])([+-]?)(?:[ \t]+([^\r\n]*))?$/.exec(header);
|
|
35
|
+
const first = node.children[0];
|
|
36
|
+
const decodedHeader = plainHeader(processor, header);
|
|
37
|
+
// A bounded header occupies one unformatted line; other variants stay source.
|
|
38
|
+
if (!match ||
|
|
39
|
+
decodedHeader == null ||
|
|
40
|
+
!kinds.has(match[2].toUpperCase()) ||
|
|
41
|
+
/^[+-](?:[ \t]|[+-])/.test(match[4] ?? '') ||
|
|
42
|
+
first?.type !== 'paragraph' ||
|
|
43
|
+
first.children[0]?.type !== 'text')
|
|
44
|
+
return {
|
|
45
|
+
type: 'inkkitLiteral',
|
|
46
|
+
value: raw,
|
|
47
|
+
position: node.position,
|
|
48
|
+
};
|
|
49
|
+
const text = first.children[0];
|
|
50
|
+
// Entities can decode to newlines without ending the authored header line.
|
|
51
|
+
const ending = /^\r?\n/.exec(text.value.slice(decodedHeader.length));
|
|
52
|
+
const lineEnd = ending ? decodedHeader.length : -1;
|
|
53
|
+
if (lineEnd < 0 && first.children.length > 1)
|
|
54
|
+
return {
|
|
55
|
+
type: 'inkkitLiteral',
|
|
56
|
+
value: raw,
|
|
57
|
+
position: node.position,
|
|
58
|
+
};
|
|
59
|
+
const children = [...node.children];
|
|
60
|
+
if (lineEnd >= 0) {
|
|
61
|
+
const remaining = text.value.slice(lineEnd + ending[0].length);
|
|
62
|
+
const firstStart = text.position?.start.offset;
|
|
63
|
+
const token = firstStart == null
|
|
64
|
+
? ''
|
|
65
|
+
: source.slice(firstStart, text.position?.end.offset);
|
|
66
|
+
const boundary = /\r?\n[ \t]*>[ \t]?/.exec(token);
|
|
67
|
+
const bodyStart = firstStart == null || !boundary
|
|
68
|
+
? undefined
|
|
69
|
+
: firstStart + boundary.index + boundary[0].length;
|
|
70
|
+
const point = bodyStart == null
|
|
71
|
+
? undefined
|
|
72
|
+
: {
|
|
73
|
+
line: source.slice(0, bodyStart).split('\n').length,
|
|
74
|
+
column: bodyStart - source.lastIndexOf('\n', bodyStart - 1),
|
|
75
|
+
offset: bodyStart,
|
|
76
|
+
};
|
|
77
|
+
children[0] = {
|
|
78
|
+
...first,
|
|
79
|
+
children: [
|
|
80
|
+
...(remaining
|
|
81
|
+
? [
|
|
82
|
+
{
|
|
83
|
+
...text,
|
|
84
|
+
value: remaining,
|
|
85
|
+
position: point && text.position
|
|
86
|
+
? { start: point, end: text.position.end }
|
|
87
|
+
: undefined,
|
|
88
|
+
},
|
|
89
|
+
]
|
|
90
|
+
: []),
|
|
91
|
+
...first.children.slice(1),
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
children.shift();
|
|
97
|
+
if (!children.length)
|
|
98
|
+
children.push({ type: 'paragraph', children: [] });
|
|
99
|
+
return {
|
|
100
|
+
type: 'inkkitCallout',
|
|
101
|
+
kind: match[2].toUpperCase(),
|
|
102
|
+
marker: match[1],
|
|
103
|
+
fold: match[3],
|
|
104
|
+
title: decodedHeader
|
|
105
|
+
.slice(header.length - (match[4]?.length ?? 0))
|
|
106
|
+
.trimEnd(),
|
|
107
|
+
titleSource: match[4]?.trimEnd() ?? '',
|
|
108
|
+
listPlaceholder: parent?.type === 'listItem' && index === 0,
|
|
109
|
+
children: children.map((child) => visit(child)),
|
|
110
|
+
position: node.position,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if ('children' in node)
|
|
115
|
+
node.children = node.children.map((child, index) => visit(child, node, index));
|
|
116
|
+
return node;
|
|
117
|
+
};
|
|
118
|
+
tree.children = tree.children.map((node) => visit(node));
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export const remarkCalloutsPlugin = $remark('inkkitCallouts', () => remarkCallouts);
|
|
122
|
+
export const calloutSchema = $node('inkkit_callout', (ctx) => ({
|
|
123
|
+
group: 'block',
|
|
124
|
+
content: 'block+',
|
|
125
|
+
defining: true,
|
|
126
|
+
attrs: {
|
|
127
|
+
kind: { default: 'NOTE' },
|
|
128
|
+
marker: { default: '[!NOTE]' },
|
|
129
|
+
fold: { default: '' },
|
|
130
|
+
title: { default: '' },
|
|
131
|
+
titleSource: { default: null },
|
|
132
|
+
listPlaceholder: { default: false },
|
|
133
|
+
},
|
|
134
|
+
parseDOM: [
|
|
135
|
+
{
|
|
136
|
+
tag: 'blockquote[data-inkkit-callout]',
|
|
137
|
+
priority: 100,
|
|
138
|
+
contentElement: '.inkkit-callout-body',
|
|
139
|
+
getAttrs: (dom) => {
|
|
140
|
+
const kind = (dom.getAttribute('data-inkkit-callout') ?? '').toUpperCase();
|
|
141
|
+
const marker = dom.getAttribute('data-inkkit-marker') ?? `[!${kind}]`;
|
|
142
|
+
const fold = dom.getAttribute('data-inkkit-fold') ?? '';
|
|
143
|
+
const titleSource = dom.getAttribute('data-inkkit-title');
|
|
144
|
+
const placeholder = dom.getAttribute('data-inkkit-list-placeholder');
|
|
145
|
+
const previous = dom.previousElementSibling;
|
|
146
|
+
const titleHeader = titleSource == null
|
|
147
|
+
? undefined
|
|
148
|
+
: plainHeader(ctx.get(remarkCtx), `${marker} ${titleSource}`);
|
|
149
|
+
if (!kinds.has(kind) ||
|
|
150
|
+
!/^\[![A-Za-z]+\]$/.test(marker) ||
|
|
151
|
+
marker.slice(2, -1).toUpperCase() !== kind ||
|
|
152
|
+
!['', '+', '-'].includes(fold) ||
|
|
153
|
+
(titleSource != null &&
|
|
154
|
+
(/[\r\n]/.test(titleSource) || titleHeader == null)))
|
|
155
|
+
return false;
|
|
156
|
+
return {
|
|
157
|
+
kind,
|
|
158
|
+
marker,
|
|
159
|
+
fold,
|
|
160
|
+
title: titleHeader == null
|
|
161
|
+
? (dom.querySelector('.inkkit-callout-title')?.textContent ?? '')
|
|
162
|
+
: titleHeader.slice(marker.length + 1).trimEnd(),
|
|
163
|
+
titleSource,
|
|
164
|
+
listPlaceholder: placeholder == null
|
|
165
|
+
? dom.parentElement?.tagName === 'LI' &&
|
|
166
|
+
(!previous ||
|
|
167
|
+
(previous.tagName === 'P' &&
|
|
168
|
+
!previous.textContent &&
|
|
169
|
+
!previous.childElementCount))
|
|
170
|
+
: placeholder === 'true',
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
toDOM: (node) => [
|
|
176
|
+
'blockquote',
|
|
177
|
+
{
|
|
178
|
+
class: 'inkkit-callout',
|
|
179
|
+
'data-inkkit-callout': node.attrs.kind,
|
|
180
|
+
'data-inkkit-marker': node.attrs.marker,
|
|
181
|
+
'data-inkkit-fold': node.attrs.fold,
|
|
182
|
+
'data-inkkit-title': node.attrs.titleSource ?? node.attrs.title,
|
|
183
|
+
'data-inkkit-list-placeholder': String(node.attrs.listPlaceholder),
|
|
184
|
+
},
|
|
185
|
+
[
|
|
186
|
+
'strong',
|
|
187
|
+
{ class: 'inkkit-callout-title' },
|
|
188
|
+
node.attrs.title ||
|
|
189
|
+
String(node.attrs.kind)
|
|
190
|
+
.toLowerCase()
|
|
191
|
+
.replace(/^./, (letter) => letter.toUpperCase()),
|
|
192
|
+
],
|
|
193
|
+
['div', { class: 'inkkit-callout-body' }, 0],
|
|
194
|
+
],
|
|
195
|
+
parseMarkdown: {
|
|
196
|
+
match: (node) => node.type === 'inkkitCallout',
|
|
197
|
+
runner(state, node, type) {
|
|
198
|
+
state.openNode(type, {
|
|
199
|
+
kind: node.kind,
|
|
200
|
+
marker: node.marker,
|
|
201
|
+
fold: node.fold,
|
|
202
|
+
title: node.title,
|
|
203
|
+
titleSource: node.titleSource,
|
|
204
|
+
listPlaceholder: node.listPlaceholder,
|
|
205
|
+
});
|
|
206
|
+
state.next(node.children);
|
|
207
|
+
state.closeNode();
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
toMarkdown: {
|
|
211
|
+
match: (node) => node.type.name === 'inkkit_callout',
|
|
212
|
+
runner(state, node) {
|
|
213
|
+
const parent = state.top();
|
|
214
|
+
const first = parent?.children?.[0];
|
|
215
|
+
// Lists require a leading paragraph even when their authored first block is a callout.
|
|
216
|
+
if (node.attrs.listPlaceholder &&
|
|
217
|
+
parent?.type === 'listItem' &&
|
|
218
|
+
parent.children?.length === 1 &&
|
|
219
|
+
first?.type === 'paragraph' &&
|
|
220
|
+
first.children?.length === 1 &&
|
|
221
|
+
first.children[0]?.type === 'html' &&
|
|
222
|
+
first.children[0].value === '<br />')
|
|
223
|
+
parent.children = [];
|
|
224
|
+
state.openNode('inkkitCallout', undefined, { ...node.attrs });
|
|
225
|
+
state.next(node.content);
|
|
226
|
+
state.closeNode();
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
}));
|
|
230
|
+
export const calloutView = $prose(() => new Plugin({
|
|
231
|
+
key: new PluginKey('inkkitCalloutView'),
|
|
232
|
+
props: {
|
|
233
|
+
nodeViews: {
|
|
234
|
+
inkkit_callout(node) {
|
|
235
|
+
const dom = document.createElement('blockquote');
|
|
236
|
+
dom.className = 'inkkit-callout';
|
|
237
|
+
dom.setAttribute('data-inkkit-callout', String(node.attrs.kind));
|
|
238
|
+
const header = document.createElement('div');
|
|
239
|
+
header.className = 'inkkit-callout-header';
|
|
240
|
+
header.contentEditable = 'false';
|
|
241
|
+
const title = document.createElement('strong');
|
|
242
|
+
title.className = 'inkkit-callout-title';
|
|
243
|
+
const contentDOM = document.createElement('div');
|
|
244
|
+
contentDOM.className = 'inkkit-callout-body';
|
|
245
|
+
let folded = node.attrs.fold === '-';
|
|
246
|
+
const button = document.createElement('button');
|
|
247
|
+
button.type = 'button';
|
|
248
|
+
button.setAttribute('data-inkkit-callout-toggle', '');
|
|
249
|
+
const render = () => {
|
|
250
|
+
title.textContent =
|
|
251
|
+
node.attrs.title ||
|
|
252
|
+
String(node.attrs.kind)
|
|
253
|
+
.toLowerCase()
|
|
254
|
+
.replace(/^./, (letter) => letter.toUpperCase());
|
|
255
|
+
dom.setAttribute('data-inkkit-folded', String(folded));
|
|
256
|
+
button.hidden = !node.attrs.fold;
|
|
257
|
+
button.setAttribute('aria-expanded', String(!folded));
|
|
258
|
+
button.setAttribute('aria-label', `${folded ? 'Expand' : 'Collapse'} ${title.textContent}`);
|
|
259
|
+
button.textContent = folded ? 'Expand' : 'Collapse';
|
|
260
|
+
};
|
|
261
|
+
const toggle = () => {
|
|
262
|
+
folded = !folded;
|
|
263
|
+
render();
|
|
264
|
+
};
|
|
265
|
+
button.addEventListener('click', toggle);
|
|
266
|
+
button.addEventListener('keydown', (event) => {
|
|
267
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
event.stopPropagation();
|
|
270
|
+
toggle();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
header.append(title, button);
|
|
274
|
+
dom.append(header, contentDOM);
|
|
275
|
+
render();
|
|
276
|
+
return {
|
|
277
|
+
dom,
|
|
278
|
+
contentDOM,
|
|
279
|
+
update(next) {
|
|
280
|
+
if (next.type !== node.type)
|
|
281
|
+
return false;
|
|
282
|
+
if (next.attrs.fold !== node.attrs.fold)
|
|
283
|
+
folded = next.attrs.fold === '-';
|
|
284
|
+
node = next;
|
|
285
|
+
render();
|
|
286
|
+
return true;
|
|
287
|
+
},
|
|
288
|
+
stopEvent: (event) => header.contains(event.target),
|
|
289
|
+
ignoreMutation: (mutation) => mutation.type !== 'selection' &&
|
|
290
|
+
!contentDOM.contains(mutation.target),
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
}));
|
|
296
|
+
export const callouts = [calloutSchema, calloutView].flat();
|
package/dist/clipboard.js
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { DOMSerializer, } from '@milkdown/kit/prose/model';
|
|
2
2
|
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
3
3
|
import { $prose } from '@milkdown/kit/utils';
|
|
4
|
+
import { shareableFragment } from './comments.js';
|
|
4
5
|
// Clipboard text is the visible document, not Markdown serialization: escaping
|
|
5
6
|
// punctuation or trailing spaces here leaks source syntax into other apps.
|
|
6
7
|
export function clipboardText(content, missingImages = new Set()) {
|
|
8
|
+
content = shareableFragment(content);
|
|
7
9
|
const blocks = [];
|
|
8
|
-
content.forEach((node) =>
|
|
10
|
+
content.forEach((node) => {
|
|
11
|
+
if (node.type.name !== 'reference_definition')
|
|
12
|
+
blocks.push(nodeText(node, missingImages));
|
|
13
|
+
});
|
|
9
14
|
const inline = content.firstChild?.isInline ?? false;
|
|
10
15
|
return blocks.join(inline ? '' : '\n\n');
|
|
11
16
|
}
|
|
12
17
|
function nodeText(node, missingImages) {
|
|
18
|
+
if (node.type.name === 'inkkit_callout')
|
|
19
|
+
return `${node.attrs.title ||
|
|
20
|
+
String(node.attrs.kind)
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/^./, (letter) => letter.toUpperCase())}\n${clipboardText(node.content, missingImages)}`;
|
|
23
|
+
if (node.type.name === 'reference_definition')
|
|
24
|
+
return '';
|
|
25
|
+
if (node.type.name === 'footnote_reference')
|
|
26
|
+
return `[${node.attrs.label}]`;
|
|
27
|
+
if (node.type.name === 'footnote_definition')
|
|
28
|
+
return `[${node.attrs.label}] ${clipboardText(node.content, missingImages)}`;
|
|
13
29
|
if (node.isText)
|
|
14
30
|
return node.text ?? '';
|
|
15
31
|
if (node.type.name === 'hardbreak' || node.type.name === 'hard_break')
|
|
@@ -58,6 +74,7 @@ function nodeText(node, missingImages) {
|
|
|
58
74
|
return clipboardText(node.content, missingImages);
|
|
59
75
|
}
|
|
60
76
|
export function clipboardContent(content, schema) {
|
|
77
|
+
content = shareableFragment(content);
|
|
61
78
|
const container = document.createElement('div');
|
|
62
79
|
const serializer = DOMSerializer.fromSchema(schema);
|
|
63
80
|
// Construct image elements without a source so detached clipboard DOM never
|
|
@@ -73,6 +90,17 @@ export function clipboardContent(content, schema) {
|
|
|
73
90
|
],
|
|
74
91
|
}, serializer.marks);
|
|
75
92
|
container.append(safe.serializeFragment(content));
|
|
93
|
+
for (const definition of container.querySelectorAll('[data-inkkit-reference-definition]'))
|
|
94
|
+
definition.remove();
|
|
95
|
+
for (const reference of container.querySelectorAll('[data-inkkit-footnote-reference]')) {
|
|
96
|
+
reference.removeAttribute('tabindex');
|
|
97
|
+
reference.removeAttribute('role');
|
|
98
|
+
}
|
|
99
|
+
for (const definition of container.querySelectorAll('[data-inkkit-footnote-definition]')) {
|
|
100
|
+
const label = document.createElement('span');
|
|
101
|
+
label.textContent = `[${definition.getAttribute('data-inkkit-label')}] `;
|
|
102
|
+
definition.prepend(label);
|
|
103
|
+
}
|
|
76
104
|
return { text: clipboardText(content), html: container.innerHTML };
|
|
77
105
|
}
|
|
78
106
|
export const visibleClipboard = $prose(() => new Plugin({
|
|
@@ -83,6 +111,7 @@ export const visibleClipboard = $prose(() => new Plugin({
|
|
|
83
111
|
}));
|
|
84
112
|
/** Export a frozen document fragment; presentation URLs never enter the clipboard. */
|
|
85
113
|
export async function portableClipboard(content, schema, markdown, adapter, context) {
|
|
114
|
+
content = shareableFragment(content);
|
|
86
115
|
const base = clipboardContent(content, schema);
|
|
87
116
|
const container = document.createElement('div');
|
|
88
117
|
container.innerHTML = base.html;
|
|
@@ -100,6 +129,7 @@ export async function portableClipboard(content, schema, markdown, adapter, cont
|
|
|
100
129
|
return { element, reference, alt };
|
|
101
130
|
});
|
|
102
131
|
await Promise.all(captured.map(async ({ element, reference, alt }, index) => {
|
|
132
|
+
element.setAttribute('data-inkkit-image-slot', String(index));
|
|
103
133
|
try {
|
|
104
134
|
if (!adapter)
|
|
105
135
|
throw new Error('The image is unavailable.');
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Fragment, type Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
2
|
+
import type { EditorView } from '@milkdown/kit/prose/view';
|
|
3
|
+
import type { Literal } from 'mdast';
|
|
4
|
+
export type CommentSyntax = 'html' | 'obsidian';
|
|
5
|
+
interface Comment extends Literal {
|
|
6
|
+
type: 'inkkitCommentInline' | 'inkkitCommentBlock';
|
|
7
|
+
syntax: CommentSyntax;
|
|
8
|
+
block?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare module 'mdast' {
|
|
11
|
+
interface PhrasingContentMap {
|
|
12
|
+
inkkitCommentInline: Comment & {
|
|
13
|
+
type: 'inkkitCommentInline';
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
interface BlockContentMap {
|
|
17
|
+
inkkitCommentBlock: Comment & {
|
|
18
|
+
type: 'inkkitCommentBlock';
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
interface RootContentMap {
|
|
22
|
+
inkkitCommentInline: Comment & {
|
|
23
|
+
type: 'inkkitCommentInline';
|
|
24
|
+
};
|
|
25
|
+
inkkitCommentBlock: Comment & {
|
|
26
|
+
type: 'inkkitCommentBlock';
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
declare module 'micromark-util-types' {
|
|
31
|
+
interface TokenTypeMap {
|
|
32
|
+
inkkitCommentInline: 'inkkitCommentInline';
|
|
33
|
+
inkkitCommentBlock: 'inkkitCommentBlock';
|
|
34
|
+
inkkitCommentData: 'inkkitCommentData';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export declare function commentSource(node: ProseNode): string;
|
|
38
|
+
export interface CommentSpan {
|
|
39
|
+
start: number;
|
|
40
|
+
end: number;
|
|
41
|
+
syntax: CommentSyntax;
|
|
42
|
+
value: string;
|
|
43
|
+
block?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function literalCommentSpans(value: string): CommentSpan[];
|
|
46
|
+
export declare const remarkCommentsPlugin: import("@milkdown/kit/utils").$Remark<"remarkComments", unknown>;
|
|
47
|
+
export declare const commentInline: import("@milkdown/kit/utils").$Node;
|
|
48
|
+
export declare const commentBlock: import("@milkdown/kit/utils").$Node;
|
|
49
|
+
export declare const commentVisibility: import("@milkdown/kit/utils").$Prose;
|
|
50
|
+
export declare function setCommentVisibility(view: EditorView, visible: boolean): void;
|
|
51
|
+
export declare const comments: (import("@milkdown/kit/utils").$Node | import("@milkdown/kit/utils").$Prose)[];
|
|
52
|
+
export declare function isComment(node: ProseNode): boolean;
|
|
53
|
+
export declare function shareableFragment(content: Fragment): Fragment;
|
|
54
|
+
export declare function commentSelectionContent(doc: ProseNode, from: number, to: number, content: Fragment): Fragment;
|
|
55
|
+
export {};
|