@aicayzer/inkkit 0.0.17 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +4 -2
- package/README.md +12 -6
- package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
- package/dist/chunks/core-vtCr4MBS.js +56503 -0
- package/dist/chunks/highlight-Daj2fv_u.js +14122 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.js +2 -0
- package/dist/editor.d.ts +261 -48
- package/dist/index.d.ts +1 -7
- package/dist/index.js +5 -2
- package/dist/style.css +242 -221
- package/dist/types.d.ts +143 -18
- package/package.json +26 -15
- package/dist/autolink.d.ts +0 -1
- package/dist/autolink.js +0 -18
- package/dist/callouts.d.ts +0 -26
- package/dist/callouts.js +0 -311
- package/dist/clipboard.d.ts +0 -11
- package/dist/clipboard.js +0 -261
- package/dist/code-fences.d.ts +0 -8
- package/dist/code-fences.js +0 -166
- package/dist/comments.d.ts +0 -55
- package/dist/comments.js +0 -494
- package/dist/decorations.d.ts +0 -2
- package/dist/decorations.js +0 -67
- package/dist/dialect.d.ts +0 -9
- package/dist/dialect.js +0 -358
- package/dist/editor.js +0 -2441
- package/dist/files.d.ts +0 -40
- package/dist/files.js +0 -133
- package/dist/highlight.d.ts +0 -1
- package/dist/highlight.js +0 -136
- package/dist/image-blocks.d.ts +0 -71
- package/dist/image-blocks.js +0 -286
- package/dist/images.d.ts +0 -51
- package/dist/images.js +0 -398
- package/dist/inline-highlight.d.ts +0 -6
- package/dist/inline-highlight.js +0 -112
- package/dist/labels.d.ts +0 -36
- package/dist/labels.js +0 -34
- package/dist/linked-syntax.d.ts +0 -48
- package/dist/linked-syntax.js +0 -320
- package/dist/literals.d.ts +0 -19
- package/dist/literals.js +0 -211
- package/dist/mermaid.d.ts +0 -8
- package/dist/mermaid.js +0 -321
- package/dist/outline.d.ts +0 -22
- package/dist/outline.js +0 -79
- package/dist/paste-html.d.ts +0 -23
- package/dist/paste-html.js +0 -441
- package/dist/paste.d.ts +0 -26
- package/dist/paste.js +0 -482
- package/dist/portable-files.d.ts +0 -10
- package/dist/portable-files.js +0 -36
- package/dist/preserve.d.ts +0 -21
- package/dist/preserve.js +0 -757
- package/dist/print.d.ts +0 -7
- package/dist/print.js +0 -409
- package/dist/reference-clipboard.d.ts +0 -8
- package/dist/reference-clipboard.js +0 -201
- package/dist/references.d.ts +0 -14
- package/dist/references.js +0 -368
- package/dist/search.d.ts +0 -15
- package/dist/search.js +0 -202
- package/dist/selection.d.ts +0 -1
- package/dist/selection.js +0 -59
- package/dist/source.d.ts +0 -16
- package/dist/source.js +0 -57
- package/dist/spreadsheet.d.ts +0 -3
- package/dist/spreadsheet.js +0 -275
- package/dist/table-alignment.d.ts +0 -2
- package/dist/table-alignment.js +0 -46
- package/dist/tables.d.ts +0 -27
- package/dist/tables.js +0 -322
- package/dist/tasks.d.ts +0 -3
- package/dist/tasks.js +0 -51
- package/dist/text-ranges.d.ts +0 -29
- package/dist/text-ranges.js +0 -256
- package/dist/types.js +0 -8
- package/dist/wiki-view.d.ts +0 -21
- package/dist/wiki-view.js +0 -78
package/dist/callouts.js
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { $node, $prose, $remark } from '@milkdown/kit/utils';
|
|
2
|
-
import { editorLabels } from './labels.js';
|
|
3
|
-
import { remarkCtx } from '@milkdown/kit/core';
|
|
4
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
5
|
-
import { defaultHandlers } from 'mdast-util-to-markdown';
|
|
6
|
-
const kinds = new Set(['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION']);
|
|
7
|
-
export function revealCalloutAncestors(view, position) {
|
|
8
|
-
const node = view.domAtPos(position).node;
|
|
9
|
-
let element = node instanceof HTMLElement ? node : node.parentElement;
|
|
10
|
-
while (element && element !== view.dom) {
|
|
11
|
-
if (element.getAttribute('data-inkkit-folded') === 'true')
|
|
12
|
-
element
|
|
13
|
-
.querySelector(':scope > .inkkit-callout-header > [data-inkkit-callout-toggle]')
|
|
14
|
-
?.click();
|
|
15
|
-
element = element.parentElement;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function plainHeader(processor, source) {
|
|
19
|
-
const node = processor.parse(source).children[0];
|
|
20
|
-
return node?.type === 'paragraph' &&
|
|
21
|
-
node.children.length === 1 &&
|
|
22
|
-
node.children[0]?.type === 'text'
|
|
23
|
-
? node.children[0].value
|
|
24
|
-
: undefined;
|
|
25
|
-
}
|
|
26
|
-
const calloutHandler = (untyped, parent, state, info) => {
|
|
27
|
-
const node = untyped;
|
|
28
|
-
const body = defaultHandlers.blockquote({ type: 'blockquote', children: node.children }, parent, state, info);
|
|
29
|
-
const title = node.titleSource ?? node.title;
|
|
30
|
-
return `> ${node.marker}${node.fold}${title ? ` ${title}` : ''}\n${body}`;
|
|
31
|
-
};
|
|
32
|
-
function remarkCallouts() {
|
|
33
|
-
const processor = this;
|
|
34
|
-
const data = this.data();
|
|
35
|
-
(data.toMarkdownExtensions ??= []).push({
|
|
36
|
-
handlers: { inkkitCallout: calloutHandler },
|
|
37
|
-
});
|
|
38
|
-
return (tree, file) => {
|
|
39
|
-
const source = String(file.value).replace(/^\uFEFF/, '');
|
|
40
|
-
const visit = (node, parent, index) => {
|
|
41
|
-
if (node.type === 'blockquote') {
|
|
42
|
-
const start = node.position?.start.offset, end = node.position?.end.offset;
|
|
43
|
-
const raw = start == null || end == null ? '' : source.slice(start, end);
|
|
44
|
-
const header = /^>[ \t]*([\s\S]*?)(?:\r?\n|$)/.exec(raw)?.[1] ?? '';
|
|
45
|
-
if (header.startsWith('[!')) {
|
|
46
|
-
const match = /^(\[!([A-Za-z]+)\])([+-]?)(?:[ \t]+([^\r\n]*))?$/.exec(header);
|
|
47
|
-
const first = node.children[0];
|
|
48
|
-
const decodedHeader = plainHeader(processor, header);
|
|
49
|
-
// A bounded header occupies one unformatted line; other variants stay source.
|
|
50
|
-
if (!match ||
|
|
51
|
-
decodedHeader == null ||
|
|
52
|
-
!kinds.has(match[2].toUpperCase()) ||
|
|
53
|
-
/^[+-](?:[ \t]|[+-])/.test(match[4] ?? '') ||
|
|
54
|
-
first?.type !== 'paragraph' ||
|
|
55
|
-
first.children[0]?.type !== 'text')
|
|
56
|
-
return {
|
|
57
|
-
type: 'inkkitLiteral',
|
|
58
|
-
value: raw,
|
|
59
|
-
position: node.position,
|
|
60
|
-
};
|
|
61
|
-
const text = first.children[0];
|
|
62
|
-
// Entities can decode to newlines without ending the authored header line.
|
|
63
|
-
const ending = /^\r?\n/.exec(text.value.slice(decodedHeader.length));
|
|
64
|
-
const lineEnd = ending ? decodedHeader.length : -1;
|
|
65
|
-
if (lineEnd < 0 && first.children.length > 1)
|
|
66
|
-
return {
|
|
67
|
-
type: 'inkkitLiteral',
|
|
68
|
-
value: raw,
|
|
69
|
-
position: node.position,
|
|
70
|
-
};
|
|
71
|
-
const children = [...node.children];
|
|
72
|
-
if (lineEnd >= 0) {
|
|
73
|
-
const remaining = text.value.slice(lineEnd + ending[0].length);
|
|
74
|
-
const firstStart = text.position?.start.offset;
|
|
75
|
-
const token = firstStart == null
|
|
76
|
-
? ''
|
|
77
|
-
: source.slice(firstStart, text.position?.end.offset);
|
|
78
|
-
const boundary = /\r?\n[ \t]*>[ \t]?/.exec(token);
|
|
79
|
-
const bodyStart = firstStart == null || !boundary
|
|
80
|
-
? undefined
|
|
81
|
-
: firstStart + boundary.index + boundary[0].length;
|
|
82
|
-
const point = bodyStart == null
|
|
83
|
-
? undefined
|
|
84
|
-
: {
|
|
85
|
-
line: source.slice(0, bodyStart).split('\n').length,
|
|
86
|
-
column: bodyStart - source.lastIndexOf('\n', bodyStart - 1),
|
|
87
|
-
offset: bodyStart,
|
|
88
|
-
};
|
|
89
|
-
children[0] = {
|
|
90
|
-
...first,
|
|
91
|
-
children: [
|
|
92
|
-
...(remaining
|
|
93
|
-
? [
|
|
94
|
-
{
|
|
95
|
-
...text,
|
|
96
|
-
value: remaining,
|
|
97
|
-
position: point && text.position
|
|
98
|
-
? { start: point, end: text.position.end }
|
|
99
|
-
: undefined,
|
|
100
|
-
},
|
|
101
|
-
]
|
|
102
|
-
: []),
|
|
103
|
-
...first.children.slice(1),
|
|
104
|
-
],
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
else
|
|
108
|
-
children.shift();
|
|
109
|
-
if (!children.length)
|
|
110
|
-
children.push({ type: 'paragraph', children: [] });
|
|
111
|
-
return {
|
|
112
|
-
type: 'inkkitCallout',
|
|
113
|
-
kind: match[2].toUpperCase(),
|
|
114
|
-
marker: match[1],
|
|
115
|
-
fold: match[3],
|
|
116
|
-
title: decodedHeader
|
|
117
|
-
.slice(header.length - (match[4]?.length ?? 0))
|
|
118
|
-
.trimEnd(),
|
|
119
|
-
titleSource: match[4]?.trimEnd() ?? '',
|
|
120
|
-
listPlaceholder: parent?.type === 'listItem' && index === 0,
|
|
121
|
-
children: children.map((child) => visit(child)),
|
|
122
|
-
position: node.position,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if ('children' in node)
|
|
127
|
-
node.children = node.children.map((child, index) => visit(child, node, index));
|
|
128
|
-
return node;
|
|
129
|
-
};
|
|
130
|
-
tree.children = tree.children.map((node) => visit(node));
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
export const remarkCalloutsPlugin = $remark('inkkitCallouts', () => remarkCallouts);
|
|
134
|
-
export const calloutSchema = $node('inkkit_callout', (ctx) => ({
|
|
135
|
-
group: 'block',
|
|
136
|
-
content: 'block+',
|
|
137
|
-
defining: true,
|
|
138
|
-
attrs: {
|
|
139
|
-
kind: { default: 'NOTE' },
|
|
140
|
-
marker: { default: '[!NOTE]' },
|
|
141
|
-
fold: { default: '' },
|
|
142
|
-
title: { default: '' },
|
|
143
|
-
titleSource: { default: null },
|
|
144
|
-
listPlaceholder: { default: false },
|
|
145
|
-
},
|
|
146
|
-
parseDOM: [
|
|
147
|
-
{
|
|
148
|
-
tag: 'blockquote[data-inkkit-callout]',
|
|
149
|
-
priority: 100,
|
|
150
|
-
contentElement: '.inkkit-callout-body',
|
|
151
|
-
getAttrs: (dom) => {
|
|
152
|
-
const kind = (dom.getAttribute('data-inkkit-callout') ?? '').toUpperCase();
|
|
153
|
-
const marker = dom.getAttribute('data-inkkit-marker') ?? `[!${kind}]`;
|
|
154
|
-
const fold = dom.getAttribute('data-inkkit-fold') ?? '';
|
|
155
|
-
const titleSource = dom.getAttribute('data-inkkit-title');
|
|
156
|
-
const placeholder = dom.getAttribute('data-inkkit-list-placeholder');
|
|
157
|
-
const previous = dom.previousElementSibling;
|
|
158
|
-
const titleHeader = titleSource == null
|
|
159
|
-
? undefined
|
|
160
|
-
: plainHeader(ctx.get(remarkCtx), `${marker} ${titleSource}`);
|
|
161
|
-
if (!kinds.has(kind) ||
|
|
162
|
-
!/^\[![A-Za-z]+\]$/.test(marker) ||
|
|
163
|
-
marker.slice(2, -1).toUpperCase() !== kind ||
|
|
164
|
-
!['', '+', '-'].includes(fold) ||
|
|
165
|
-
(titleSource != null &&
|
|
166
|
-
(/[\r\n]/.test(titleSource) || titleHeader == null)))
|
|
167
|
-
return false;
|
|
168
|
-
return {
|
|
169
|
-
kind,
|
|
170
|
-
marker,
|
|
171
|
-
fold,
|
|
172
|
-
title: titleHeader == null
|
|
173
|
-
? (dom.querySelector('.inkkit-callout-title')?.textContent ?? '')
|
|
174
|
-
: titleHeader.slice(marker.length + 1).trimEnd(),
|
|
175
|
-
titleSource,
|
|
176
|
-
listPlaceholder: placeholder == null
|
|
177
|
-
? dom.parentElement?.tagName === 'LI' &&
|
|
178
|
-
(!previous ||
|
|
179
|
-
(previous.tagName === 'P' &&
|
|
180
|
-
!previous.textContent &&
|
|
181
|
-
!previous.childElementCount))
|
|
182
|
-
: placeholder === 'true',
|
|
183
|
-
};
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
toDOM: (node) => [
|
|
188
|
-
'blockquote',
|
|
189
|
-
{
|
|
190
|
-
class: 'inkkit-callout',
|
|
191
|
-
'data-inkkit-callout': node.attrs.kind,
|
|
192
|
-
'data-inkkit-marker': node.attrs.marker,
|
|
193
|
-
'data-inkkit-fold': node.attrs.fold,
|
|
194
|
-
'data-inkkit-title': node.attrs.titleSource ?? node.attrs.title,
|
|
195
|
-
'data-inkkit-list-placeholder': String(node.attrs.listPlaceholder),
|
|
196
|
-
},
|
|
197
|
-
[
|
|
198
|
-
'strong',
|
|
199
|
-
{ class: 'inkkit-callout-title' },
|
|
200
|
-
node.attrs.title ||
|
|
201
|
-
String(node.attrs.kind)
|
|
202
|
-
.toLowerCase()
|
|
203
|
-
.replace(/^./, (letter) => letter.toUpperCase()),
|
|
204
|
-
],
|
|
205
|
-
['div', { class: 'inkkit-callout-body' }, 0],
|
|
206
|
-
],
|
|
207
|
-
parseMarkdown: {
|
|
208
|
-
match: (node) => node.type === 'inkkitCallout',
|
|
209
|
-
runner(state, node, type) {
|
|
210
|
-
state.openNode(type, {
|
|
211
|
-
kind: node.kind,
|
|
212
|
-
marker: node.marker,
|
|
213
|
-
fold: node.fold,
|
|
214
|
-
title: node.title,
|
|
215
|
-
titleSource: node.titleSource,
|
|
216
|
-
listPlaceholder: node.listPlaceholder,
|
|
217
|
-
});
|
|
218
|
-
state.next(node.children);
|
|
219
|
-
state.closeNode();
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
toMarkdown: {
|
|
223
|
-
match: (node) => node.type.name === 'inkkit_callout',
|
|
224
|
-
runner(state, node) {
|
|
225
|
-
const parent = state.top();
|
|
226
|
-
const first = parent?.children?.[0];
|
|
227
|
-
// Lists require a leading paragraph even when their authored first block is a callout.
|
|
228
|
-
if (node.attrs.listPlaceholder &&
|
|
229
|
-
parent?.type === 'listItem' &&
|
|
230
|
-
parent.children?.length === 1 &&
|
|
231
|
-
first?.type === 'paragraph' &&
|
|
232
|
-
first.children?.length === 1 &&
|
|
233
|
-
first.children[0]?.type === 'html' &&
|
|
234
|
-
first.children[0].value === '<br />')
|
|
235
|
-
parent.children = [];
|
|
236
|
-
state.openNode('inkkitCallout', undefined, { ...node.attrs });
|
|
237
|
-
state.next(node.content);
|
|
238
|
-
state.closeNode();
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
}));
|
|
242
|
-
export const calloutView = $prose((ctx) => new Plugin({
|
|
243
|
-
key: new PluginKey('inkkitCalloutView'),
|
|
244
|
-
props: {
|
|
245
|
-
nodeViews: {
|
|
246
|
-
inkkit_callout(node, view) {
|
|
247
|
-
const dom = document.createElement('blockquote');
|
|
248
|
-
dom.className = 'inkkit-callout';
|
|
249
|
-
dom.setAttribute('data-inkkit-callout', String(node.attrs.kind));
|
|
250
|
-
const header = document.createElement('div');
|
|
251
|
-
header.className = 'inkkit-callout-header';
|
|
252
|
-
header.contentEditable = 'false';
|
|
253
|
-
const title = document.createElement('strong');
|
|
254
|
-
title.className = 'inkkit-callout-title';
|
|
255
|
-
const contentDOM = document.createElement('div');
|
|
256
|
-
contentDOM.className = 'inkkit-callout-body';
|
|
257
|
-
let folded = node.attrs.fold === '-';
|
|
258
|
-
const button = document.createElement('button');
|
|
259
|
-
button.type = 'button';
|
|
260
|
-
button.setAttribute('data-inkkit-callout-toggle', '');
|
|
261
|
-
const render = () => {
|
|
262
|
-
title.textContent =
|
|
263
|
-
node.attrs.title ||
|
|
264
|
-
String(node.attrs.kind)
|
|
265
|
-
.toLowerCase()
|
|
266
|
-
.replace(/^./, (letter) => letter.toUpperCase());
|
|
267
|
-
dom.setAttribute('data-inkkit-folded', String(folded));
|
|
268
|
-
view.dom.dispatchEvent(new Event('inkkit-media-policy'));
|
|
269
|
-
button.hidden = !node.attrs.fold;
|
|
270
|
-
button.setAttribute('aria-expanded', String(!folded));
|
|
271
|
-
button.setAttribute('aria-label', `${folded ? editorLabels(ctx).expandCallout : editorLabels(ctx).collapseCallout} ${title.textContent}`);
|
|
272
|
-
button.textContent = folded
|
|
273
|
-
? editorLabels(ctx).expandCallout
|
|
274
|
-
: editorLabels(ctx).collapseCallout;
|
|
275
|
-
};
|
|
276
|
-
const toggle = () => {
|
|
277
|
-
folded = !folded;
|
|
278
|
-
render();
|
|
279
|
-
};
|
|
280
|
-
button.addEventListener('click', toggle);
|
|
281
|
-
button.addEventListener('keydown', (event) => {
|
|
282
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
283
|
-
event.preventDefault();
|
|
284
|
-
event.stopPropagation();
|
|
285
|
-
toggle();
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
header.append(title, button);
|
|
289
|
-
dom.append(header, contentDOM);
|
|
290
|
-
render();
|
|
291
|
-
return {
|
|
292
|
-
dom,
|
|
293
|
-
contentDOM,
|
|
294
|
-
update(next) {
|
|
295
|
-
if (next.type !== node.type)
|
|
296
|
-
return false;
|
|
297
|
-
if (next.attrs.fold !== node.attrs.fold)
|
|
298
|
-
folded = next.attrs.fold === '-';
|
|
299
|
-
node = next;
|
|
300
|
-
render();
|
|
301
|
-
return true;
|
|
302
|
-
},
|
|
303
|
-
stopEvent: (event) => header.contains(event.target),
|
|
304
|
-
ignoreMutation: (mutation) => mutation.type !== 'selection' &&
|
|
305
|
-
!contentDOM.contains(mutation.target),
|
|
306
|
-
};
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
}));
|
|
311
|
-
export const callouts = [calloutSchema, calloutView].flat();
|
package/dist/clipboard.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type Fragment, type Schema } from '@milkdown/kit/prose/model';
|
|
2
|
-
import type { ClipboardOutput, DocumentContext, ImageAdapter, FileAdapter } from './types.js';
|
|
3
|
-
export interface ClipboardContent {
|
|
4
|
-
text: string;
|
|
5
|
-
html: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function clipboardText(content: Fragment, missingImages?: ReadonlySet<string>, fileDescriptions?: ReadonlyMap<object, string>): string;
|
|
8
|
-
export declare function clipboardContent(content: Fragment, schema: Schema): ClipboardContent;
|
|
9
|
-
export declare const visibleClipboard: import("@milkdown/kit/utils").$Prose;
|
|
10
|
-
/** Export a frozen document fragment; presentation URLs never enter the clipboard. */
|
|
11
|
-
export declare function portableClipboard(content: Fragment, schema: Schema, markdown: string, adapter: ImageAdapter | undefined, context: DocumentContext, completeDiagrams?: ReadonlySet<string>, files?: FileAdapter, signal?: AbortSignal): Promise<ClipboardOutput>;
|
package/dist/clipboard.js
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { DOMSerializer, } from '@milkdown/kit/prose/model';
|
|
2
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
3
|
-
import { $prose } from '@milkdown/kit/utils';
|
|
4
|
-
import { shareableFragment } from './comments.js';
|
|
5
|
-
import { diagramImage } from './mermaid.js';
|
|
6
|
-
import { fileReference } from './linked-syntax.js';
|
|
7
|
-
import { portableFile, portableFileImage } from './portable-files.js';
|
|
8
|
-
import { withFileSignal } from './files.js';
|
|
9
|
-
// Clipboard text is the visible document, not Markdown serialization: escaping
|
|
10
|
-
// punctuation or trailing spaces here leaks source syntax into other apps.
|
|
11
|
-
export function clipboardText(content, missingImages = new Set(), fileDescriptions = new Map()) {
|
|
12
|
-
content = shareableFragment(content);
|
|
13
|
-
const blocks = [];
|
|
14
|
-
content.forEach((node) => {
|
|
15
|
-
if (node.type.name !== 'reference_definition')
|
|
16
|
-
blocks.push(nodeText(node, missingImages, fileDescriptions));
|
|
17
|
-
});
|
|
18
|
-
const inline = content.firstChild?.isInline ?? false;
|
|
19
|
-
return blocks.join(inline ? '' : '\n\n');
|
|
20
|
-
}
|
|
21
|
-
function nodeText(node, missingImages, fileDescriptions) {
|
|
22
|
-
if (node.type.name === 'inkkit_wiki_link')
|
|
23
|
-
return String(node.attrs.label || node.attrs.target || 'Link');
|
|
24
|
-
if (node.type.name === 'inkkit_callout')
|
|
25
|
-
return `${node.attrs.title ||
|
|
26
|
-
String(node.attrs.kind)
|
|
27
|
-
.toLowerCase()
|
|
28
|
-
.replace(/^./, (letter) => letter.toUpperCase())}\n${clipboardText(node.content, missingImages, fileDescriptions)}`;
|
|
29
|
-
if (node.type.name === 'reference_definition')
|
|
30
|
-
return '';
|
|
31
|
-
if (node.type.name === 'footnote_reference')
|
|
32
|
-
return `[${node.attrs.label}]`;
|
|
33
|
-
if (node.type.name === 'footnote_definition')
|
|
34
|
-
return `[${node.attrs.label}] ${clipboardText(node.content, missingImages, fileDescriptions)}`;
|
|
35
|
-
if (node.isText)
|
|
36
|
-
return node.text ?? '';
|
|
37
|
-
if (node.type.name === 'hardbreak' || node.type.name === 'hard_break')
|
|
38
|
-
return '\n';
|
|
39
|
-
if (node.type.name === 'bullet_list' || node.type.name === 'ordered_list') {
|
|
40
|
-
const items = [];
|
|
41
|
-
node.forEach((item, _offset, index) => {
|
|
42
|
-
const marker = node.type.name === 'ordered_list'
|
|
43
|
-
? `${Number(node.attrs.order ?? 1) + index}. `
|
|
44
|
-
: '- ';
|
|
45
|
-
const task = item.attrs.checked == null ? '' : item.attrs.checked ? '[x] ' : '[ ] ';
|
|
46
|
-
const prefix = marker + task;
|
|
47
|
-
const indent = ' '.repeat(marker.length);
|
|
48
|
-
const blocks = [];
|
|
49
|
-
item.forEach((child, _childOffset, childIndex) => {
|
|
50
|
-
const text = nodeText(child, missingImages, fileDescriptions);
|
|
51
|
-
const nestedList = child.type.name === 'bullet_list' ||
|
|
52
|
-
child.type.name === 'ordered_list';
|
|
53
|
-
const lines = text.split('\n');
|
|
54
|
-
const indented = lines
|
|
55
|
-
.map((line, lineIndex) => childIndex === 0 && lineIndex === 0 ? prefix + line : indent + line)
|
|
56
|
-
.join('\n');
|
|
57
|
-
// Nested lists follow their parent directly; subsequent paragraphs keep
|
|
58
|
-
// their blank line and every continuation stays inside its list item.
|
|
59
|
-
blocks.push((childIndex > 0 && !nestedList ? '\n' : '') + indented);
|
|
60
|
-
});
|
|
61
|
-
items.push(blocks.length ? blocks.join('\n') : prefix.trimEnd());
|
|
62
|
-
});
|
|
63
|
-
return items.join('\n');
|
|
64
|
-
}
|
|
65
|
-
if (node.type.name === 'image') {
|
|
66
|
-
const description = fileDescriptions.get(node.attrs);
|
|
67
|
-
if (description != null)
|
|
68
|
-
return description;
|
|
69
|
-
const alt = fileReference(node).label || 'Image';
|
|
70
|
-
return missingImages.has(String(node.attrs.src ?? ''))
|
|
71
|
-
? `[${alt}: image unavailable]`
|
|
72
|
-
: alt;
|
|
73
|
-
}
|
|
74
|
-
if (node.type.name === 'table') {
|
|
75
|
-
const rows = [];
|
|
76
|
-
node.forEach((row) => {
|
|
77
|
-
const cells = [];
|
|
78
|
-
row.forEach((cell) => cells.push(clipboardText(cell.content, missingImages, fileDescriptions)));
|
|
79
|
-
rows.push(cells.join('\t'));
|
|
80
|
-
});
|
|
81
|
-
return rows.join('\n');
|
|
82
|
-
}
|
|
83
|
-
return clipboardText(node.content, missingImages, fileDescriptions);
|
|
84
|
-
}
|
|
85
|
-
export function clipboardContent(content, schema) {
|
|
86
|
-
content = shareableFragment(content);
|
|
87
|
-
const container = document.createElement('div');
|
|
88
|
-
const serializer = DOMSerializer.fromSchema(schema);
|
|
89
|
-
// Construct image elements without a source so detached clipboard DOM never
|
|
90
|
-
// fetches authored references or temporary presentation URLs.
|
|
91
|
-
const safe = new DOMSerializer({
|
|
92
|
-
...serializer.nodes,
|
|
93
|
-
inkkit_wiki_link: (node) => [
|
|
94
|
-
'span',
|
|
95
|
-
String(node.attrs.label || node.attrs.target || 'Link'),
|
|
96
|
-
],
|
|
97
|
-
image: (node) => [
|
|
98
|
-
'img',
|
|
99
|
-
{
|
|
100
|
-
alt: String(node.attrs.alt ?? ''),
|
|
101
|
-
title: String(node.attrs.title ?? ''),
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
}, serializer.marks);
|
|
105
|
-
container.append(safe.serializeFragment(content));
|
|
106
|
-
for (const definition of container.querySelectorAll('[data-inkkit-reference-definition]'))
|
|
107
|
-
definition.remove();
|
|
108
|
-
for (const reference of container.querySelectorAll('[data-inkkit-footnote-reference]')) {
|
|
109
|
-
reference.removeAttribute('tabindex');
|
|
110
|
-
reference.removeAttribute('role');
|
|
111
|
-
}
|
|
112
|
-
for (const definition of container.querySelectorAll('[data-inkkit-footnote-definition]')) {
|
|
113
|
-
const label = document.createElement('span');
|
|
114
|
-
label.textContent = `[${definition.getAttribute('data-inkkit-label')}] `;
|
|
115
|
-
definition.prepend(label);
|
|
116
|
-
}
|
|
117
|
-
return { text: clipboardText(content), html: container.innerHTML };
|
|
118
|
-
}
|
|
119
|
-
export const visibleClipboard = $prose(() => new Plugin({
|
|
120
|
-
key: new PluginKey('visibleClipboard'),
|
|
121
|
-
props: {
|
|
122
|
-
clipboardTextSerializer: (slice) => clipboardText(slice.content),
|
|
123
|
-
},
|
|
124
|
-
}));
|
|
125
|
-
/** Export a frozen document fragment; presentation URLs never enter the clipboard. */
|
|
126
|
-
export async function portableClipboard(content, schema, markdown, adapter, context, completeDiagrams, files, signal = new AbortController().signal) {
|
|
127
|
-
signal.throwIfAborted();
|
|
128
|
-
content = shareableFragment(content);
|
|
129
|
-
const base = clipboardContent(content, schema);
|
|
130
|
-
const container = document.createElement('div');
|
|
131
|
-
container.innerHTML = base.html;
|
|
132
|
-
const images = [];
|
|
133
|
-
const references = [];
|
|
134
|
-
const fileDescriptions = new Map();
|
|
135
|
-
content.descendants((node) => {
|
|
136
|
-
if (node.type.name === 'image')
|
|
137
|
-
references.push(node);
|
|
138
|
-
});
|
|
139
|
-
const captured = [...container.querySelectorAll('img')].map((element, index) => {
|
|
140
|
-
const node = references[index];
|
|
141
|
-
const reference = String(node?.attrs.src ?? '');
|
|
142
|
-
const { label: authoredAlt, width } = fileReference(node);
|
|
143
|
-
const alt = authoredAlt || 'Image';
|
|
144
|
-
if (width != null && width > 0)
|
|
145
|
-
element.setAttribute('width', String(Math.min(4096, width)));
|
|
146
|
-
element.removeAttribute('src');
|
|
147
|
-
element.removeAttribute('srcset');
|
|
148
|
-
return { element, node, reference, alt };
|
|
149
|
-
});
|
|
150
|
-
await Promise.all(captured.map(async ({ element, node, reference, alt }, index) => {
|
|
151
|
-
let label = alt;
|
|
152
|
-
element.setAttribute('data-inkkit-image-slot', String(index));
|
|
153
|
-
element.setAttribute('data-inkkit-authored-image-slot', String(index));
|
|
154
|
-
try {
|
|
155
|
-
const file = files
|
|
156
|
-
? await portableFile(node, files, context, signal)
|
|
157
|
-
: undefined;
|
|
158
|
-
if (file && file.presentation.kind !== 'image') {
|
|
159
|
-
const fallback = document.createElement('span');
|
|
160
|
-
fallback.textContent = file.description;
|
|
161
|
-
element.replaceWith(fallback);
|
|
162
|
-
fileDescriptions.set(node.attrs, file.description);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
label = file?.label || alt;
|
|
166
|
-
if (!files && !adapter)
|
|
167
|
-
throw new Error('The image is unavailable.');
|
|
168
|
-
const input = file
|
|
169
|
-
? await portableFileImage(file, files, adapter, context, signal)
|
|
170
|
-
: await withFileSignal(adapter.exportImage(reference, { ...context }), signal);
|
|
171
|
-
signal.throwIfAborted();
|
|
172
|
-
const image = { ...input, bytes: new Uint8Array(input.bytes) };
|
|
173
|
-
if (!/^image\/(png|jpeg|gif|webp|avif|bmp|tiff)$/i.test(image.mimeType))
|
|
174
|
-
throw new Error('The image format cannot be exported.');
|
|
175
|
-
let binary = '';
|
|
176
|
-
for (const byte of image.bytes)
|
|
177
|
-
binary += String.fromCharCode(byte);
|
|
178
|
-
const portable = `data:${image.mimeType};base64,${btoa(binary)}`;
|
|
179
|
-
element.setAttribute('src', portable);
|
|
180
|
-
element.setAttribute('alt', label);
|
|
181
|
-
fileDescriptions.set(node.attrs, label);
|
|
182
|
-
images[index] = { reference, alt: label, image };
|
|
183
|
-
}
|
|
184
|
-
catch (error) {
|
|
185
|
-
signal.throwIfAborted();
|
|
186
|
-
const message = error instanceof Error ? error.message : 'The image is unavailable.';
|
|
187
|
-
const warning = document.createElement('span');
|
|
188
|
-
warning.textContent = `[${label}: image unavailable]`;
|
|
189
|
-
element.replaceWith(warning);
|
|
190
|
-
fileDescriptions.set(node.attrs, warning.textContent);
|
|
191
|
-
images[index] = { reference, alt: label, error: message };
|
|
192
|
-
}
|
|
193
|
-
}));
|
|
194
|
-
const diagrams = [];
|
|
195
|
-
for (const code of container.querySelectorAll('pre[data-language="mermaid"] > code')) {
|
|
196
|
-
const source = code.textContent ?? '';
|
|
197
|
-
if (completeDiagrams && !completeDiagrams.has(source))
|
|
198
|
-
continue;
|
|
199
|
-
const result = { source };
|
|
200
|
-
diagrams.push(result);
|
|
201
|
-
try {
|
|
202
|
-
const image = await withFileSignal(diagramImage(source), signal);
|
|
203
|
-
let binary = '';
|
|
204
|
-
for (const byte of image.bytes)
|
|
205
|
-
binary += String.fromCharCode(byte);
|
|
206
|
-
const figure = document.createElement('figure');
|
|
207
|
-
figure.setAttribute('data-inkkit-mermaid', source);
|
|
208
|
-
const fence = code.parentElement.getAttribute('data-inkkit-fence');
|
|
209
|
-
if (fence)
|
|
210
|
-
figure.setAttribute('data-inkkit-fence', fence);
|
|
211
|
-
const element = document.createElement('img');
|
|
212
|
-
element.src = `data:image/png;base64,${btoa(binary)}`;
|
|
213
|
-
element.alt = `Mermaid diagram: ${source}`;
|
|
214
|
-
figure.append(element);
|
|
215
|
-
code.parentElement.replaceWith(figure);
|
|
216
|
-
result.image = image;
|
|
217
|
-
}
|
|
218
|
-
catch (error) {
|
|
219
|
-
signal.throwIfAborted();
|
|
220
|
-
result.error =
|
|
221
|
-
error instanceof Error
|
|
222
|
-
? error.message
|
|
223
|
-
: 'The diagram could not be exported.';
|
|
224
|
-
const warning = document.createElement('p');
|
|
225
|
-
warning.setAttribute('data-inkkit-diagram-error', '');
|
|
226
|
-
warning.textContent = `Diagram unavailable: ${result.error}`;
|
|
227
|
-
code.parentElement.before(warning);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// Native attachment slots follow DOM order, including generated diagrams.
|
|
231
|
-
const orderedImages = [];
|
|
232
|
-
for (const element of container.querySelectorAll('img')) {
|
|
233
|
-
const diagram = element.closest('[data-inkkit-mermaid]');
|
|
234
|
-
const item = diagram
|
|
235
|
-
? {
|
|
236
|
-
reference: '',
|
|
237
|
-
alt: element.alt,
|
|
238
|
-
image: diagrams.find((entry) => entry.source === diagram.getAttribute('data-inkkit-mermaid')).image,
|
|
239
|
-
}
|
|
240
|
-
: images[Number(element.getAttribute('data-inkkit-image-slot'))];
|
|
241
|
-
element.setAttribute('data-inkkit-image-slot', String(orderedImages.length));
|
|
242
|
-
orderedImages.push(item);
|
|
243
|
-
}
|
|
244
|
-
// Scriptable links and event attributes are not part of semantic rich text.
|
|
245
|
-
for (const element of container.querySelectorAll('*')) {
|
|
246
|
-
for (const attribute of [...element.attributes])
|
|
247
|
-
if (attribute.name.startsWith('on') ||
|
|
248
|
-
((attribute.name === 'href' || attribute.name === 'src') &&
|
|
249
|
-
/^javascript:/i.test(attribute.value)))
|
|
250
|
-
element.removeAttribute(attribute.name);
|
|
251
|
-
}
|
|
252
|
-
const missing = new Set(images.filter((image) => image?.error).map((image) => image.reference));
|
|
253
|
-
signal.throwIfAborted();
|
|
254
|
-
return {
|
|
255
|
-
text: clipboardText(content, missing, fileDescriptions),
|
|
256
|
-
html: container.innerHTML,
|
|
257
|
-
markdown,
|
|
258
|
-
images: [...orderedImages, ...images.filter((image) => image?.error)],
|
|
259
|
-
diagrams,
|
|
260
|
-
};
|
|
261
|
-
}
|
package/dist/code-fences.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type Options } from 'mdast-util-to-markdown';
|
|
2
|
-
import type { Ctx } from '@milkdown/kit/ctx';
|
|
3
|
-
import type { Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
4
|
-
export declare const remarkCodeFences: import("@milkdown/kit/utils").$Remark<"codeFences", unknown>;
|
|
5
|
-
export declare const preservingCodeBlocks: import("@milkdown/kit/utils").$NodeSchema<"code_block">;
|
|
6
|
-
export declare const fencedCodeHandler: NonNullable<Options['handlers']>['code'];
|
|
7
|
-
export declare function restoreCodeEndings(ctx: Ctx, doc: ProseNode, markdown: string): string;
|
|
8
|
-
export declare function finalCodeEnding(doc: ProseNode): string | undefined;
|