@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/paste.js
DELETED
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
import { editorViewCtx, parserCtx } from '@milkdown/kit/core';
|
|
2
|
-
import { DOMParser as ProseParser, DOMSerializer, Fragment, Slice, } from '@milkdown/kit/prose/model';
|
|
3
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
4
|
-
import { $prose } from '@milkdown/kit/utils';
|
|
5
|
-
import { pasteSpreadsheet } from './spreadsheet.js';
|
|
6
|
-
import { isImage } from './image-blocks.js';
|
|
7
|
-
import { collapseClipboardWhitespace, isRewrittenElement, isRichElement, normalizeClipboardHTML, } from './paste-html.js';
|
|
8
|
-
import { avoidReferenceCollisions, markdownFromHTML, } from './reference-clipboard.js';
|
|
9
|
-
import { InkKitError, } from './types.js';
|
|
10
|
-
export class PasteController {
|
|
11
|
-
options;
|
|
12
|
-
active;
|
|
13
|
-
key = new PluginKey('inkkitPaste');
|
|
14
|
-
dead = false;
|
|
15
|
-
get pending() {
|
|
16
|
-
return this.active != null;
|
|
17
|
-
}
|
|
18
|
-
plugin;
|
|
19
|
-
constructor(options) {
|
|
20
|
-
this.options = options;
|
|
21
|
-
this.plugin = $prose(() => new Plugin({
|
|
22
|
-
key: this.key,
|
|
23
|
-
state: {
|
|
24
|
-
init: () => null,
|
|
25
|
-
apply: (transaction, previous) => {
|
|
26
|
-
if (!this.active)
|
|
27
|
-
return null;
|
|
28
|
-
const anchor = previous?.operation === this.active ? previous : this.active;
|
|
29
|
-
return {
|
|
30
|
-
operation: this.active,
|
|
31
|
-
from: transaction.mapping.map(anchor.from, 1),
|
|
32
|
-
to: transaction.mapping.map(anchor.to, anchor.from === anchor.to ? 1 : -1),
|
|
33
|
-
};
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
props: {
|
|
37
|
-
handlePaste: (view, event) => {
|
|
38
|
-
const data = event.clipboardData;
|
|
39
|
-
if (!data || !view.editable)
|
|
40
|
-
return false;
|
|
41
|
-
if (view.state.selection.$from.parent.type.spec.code)
|
|
42
|
-
return false;
|
|
43
|
-
const text = data.getData('text/plain');
|
|
44
|
-
const html = data.getData('text/html');
|
|
45
|
-
const metadata = data.getData('vscode-editor-data');
|
|
46
|
-
if (metadata) {
|
|
47
|
-
try {
|
|
48
|
-
const value = JSON.parse(metadata);
|
|
49
|
-
if (!value ||
|
|
50
|
-
typeof value !== 'object' ||
|
|
51
|
-
!('mode' in value) ||
|
|
52
|
-
typeof value.mode !== 'string')
|
|
53
|
-
throw new Error('Invalid VS Code clipboard metadata');
|
|
54
|
-
// Retain the provider's code-language behaviour for valid metadata.
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
void this.paste({ text, plainText: true }).catch((error) => options.onError?.(error));
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const files = [...data.files].filter((file) => file.type.startsWith('image/'));
|
|
63
|
-
void this.run({
|
|
64
|
-
text,
|
|
65
|
-
html,
|
|
66
|
-
plainText: this.options.literalText?.() ?? false,
|
|
67
|
-
}, files).catch((error) => options.onError?.(error));
|
|
68
|
-
return true;
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
paste(input) {
|
|
74
|
-
return this.run(input);
|
|
75
|
-
}
|
|
76
|
-
anchor(operation) {
|
|
77
|
-
const mapped = this.key.getState(this.options.ctx().get(editorViewCtx).state);
|
|
78
|
-
return mapped?.operation === operation ? mapped : operation;
|
|
79
|
-
}
|
|
80
|
-
cancelPending() {
|
|
81
|
-
this.active = undefined;
|
|
82
|
-
this.options.onPendingChanged?.();
|
|
83
|
-
}
|
|
84
|
-
destroy() {
|
|
85
|
-
this.dead = true;
|
|
86
|
-
this.cancelPending();
|
|
87
|
-
}
|
|
88
|
-
assertContext(context, operation) {
|
|
89
|
-
if (this.dead)
|
|
90
|
-
throw new InkKitError('destroyed', 'The editor was destroyed.');
|
|
91
|
-
const current = this.options.context();
|
|
92
|
-
if (this.active !== operation ||
|
|
93
|
-
current.documentId !== context.documentId ||
|
|
94
|
-
current.generation !== context.generation)
|
|
95
|
-
throw new InkKitError('stale-document', 'The document changed while images were importing.');
|
|
96
|
-
}
|
|
97
|
-
async run(input, files = []) {
|
|
98
|
-
if (this.dead)
|
|
99
|
-
throw new InkKitError('destroyed', 'The editor was destroyed.');
|
|
100
|
-
if (this.pending)
|
|
101
|
-
throw new InkKitError('operation-pending', 'An image paste is still pending.');
|
|
102
|
-
const context = { ...this.options.context() };
|
|
103
|
-
const ctx = this.options.ctx();
|
|
104
|
-
const view = ctx.get(editorViewCtx);
|
|
105
|
-
if (!view.editable || this.options.editable?.() === false)
|
|
106
|
-
return;
|
|
107
|
-
if (view.composing)
|
|
108
|
-
throw new InkKitError('composition', 'Finish composing text before pasting.');
|
|
109
|
-
const operation = {
|
|
110
|
-
from: view.state.selection.from,
|
|
111
|
-
to: view.state.selection.to,
|
|
112
|
-
};
|
|
113
|
-
this.active = operation;
|
|
114
|
-
this.options.onPendingChanged?.();
|
|
115
|
-
try {
|
|
116
|
-
const images = [...(input.images ?? [])];
|
|
117
|
-
for (const file of files)
|
|
118
|
-
images.push({
|
|
119
|
-
bytes: new Uint8Array(await file.arrayBuffer()),
|
|
120
|
-
mimeType: file.type,
|
|
121
|
-
filename: file.name,
|
|
122
|
-
});
|
|
123
|
-
this.assertContext(context, operation);
|
|
124
|
-
const schema = view.state.schema;
|
|
125
|
-
let slice;
|
|
126
|
-
const plainText = input.plainText ||
|
|
127
|
-
this.options.literalText?.() ||
|
|
128
|
-
view.state.selection.$from.parent.type.spec.code;
|
|
129
|
-
if (!plainText &&
|
|
130
|
-
input.markdown == null &&
|
|
131
|
-
pasteSpreadsheet(ctx, { ...input, images }))
|
|
132
|
-
return;
|
|
133
|
-
const markdown = plainText
|
|
134
|
-
? undefined
|
|
135
|
-
: (input.markdown ??
|
|
136
|
-
(input.html ? markdownFromHTML(input.html) : undefined));
|
|
137
|
-
if (plainText) {
|
|
138
|
-
if (view.state.selection.$from.parent.type.spec.code) {
|
|
139
|
-
const anchor = this.anchor(operation);
|
|
140
|
-
view.dispatch(view.state.tr.insertText(input.text, anchor.from, anchor.to));
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
const paragraphs = input.text
|
|
144
|
-
.replace(/\r\n?/g, '\n')
|
|
145
|
-
.split('\n')
|
|
146
|
-
.map((line) => schema.nodes.paragraph.create(null, line ? schema.text(line) : undefined));
|
|
147
|
-
slice = new Slice(Fragment.fromArray(paragraphs), 1, 1);
|
|
148
|
-
}
|
|
149
|
-
else if (input.html) {
|
|
150
|
-
// Template contents remain inert while unsupported source is replaced
|
|
151
|
-
// and managed image references are imported.
|
|
152
|
-
const template = document.createElement('template');
|
|
153
|
-
template.innerHTML = input.html;
|
|
154
|
-
const container = template.content;
|
|
155
|
-
// Preserve whole unsupported tables before rewriting their descendants,
|
|
156
|
-
// so comments retain their source and ordinary-copy privacy.
|
|
157
|
-
for (const table of [...container.querySelectorAll('table')]) {
|
|
158
|
-
if (table.parentElement?.closest('table'))
|
|
159
|
-
continue;
|
|
160
|
-
// Inside an element that stays literal source, the whole element is
|
|
161
|
-
// kept as written, so its tables are not rewritten or judged here.
|
|
162
|
-
if (!insideRewrittenContent(table))
|
|
163
|
-
continue;
|
|
164
|
-
if (schema.nodes.table) {
|
|
165
|
-
// Judge the table as it will import, so wrappers such as `u` or
|
|
166
|
-
// `label` in a cell do not make it literal. A table that is still
|
|
167
|
-
// unsupported keeps its original source. An input in a cell would
|
|
168
|
-
// be dropped with its state, so that table stays source too.
|
|
169
|
-
const trial = table.cloneNode(true);
|
|
170
|
-
const holder = table.ownerDocument.createDocumentFragment();
|
|
171
|
-
holder.append(trial);
|
|
172
|
-
normalizeClipboardHTML(holder);
|
|
173
|
-
if (!table.querySelector('td input,th input') &&
|
|
174
|
-
!unsupportedClipboardTable(trial)) {
|
|
175
|
-
table.replaceWith(trial);
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
const preserved = ctx.get(parserCtx)(table.outerHTML);
|
|
180
|
-
table.replaceWith(DOMSerializer.fromSchema(schema).serializeFragment(preserved.content));
|
|
181
|
-
}
|
|
182
|
-
for (const warning of container.querySelectorAll('[data-inkkit-diagram-error]'))
|
|
183
|
-
warning.remove();
|
|
184
|
-
for (const diagram of container.querySelectorAll('figure[data-inkkit-mermaid]')) {
|
|
185
|
-
const source = diagram.getAttribute('data-inkkit-mermaid') ?? '';
|
|
186
|
-
if (source.length > 30000)
|
|
187
|
-
continue;
|
|
188
|
-
const pre = document.createElement('pre');
|
|
189
|
-
pre.dataset.language = 'mermaid';
|
|
190
|
-
const fence = diagram.getAttribute('data-inkkit-fence');
|
|
191
|
-
if (fence)
|
|
192
|
-
pre.setAttribute('data-inkkit-fence', fence);
|
|
193
|
-
const code = document.createElement('code');
|
|
194
|
-
code.className = 'language-mermaid';
|
|
195
|
-
code.textContent = source;
|
|
196
|
-
pre.append(code);
|
|
197
|
-
diagram.replaceWith(pre);
|
|
198
|
-
}
|
|
199
|
-
if (markdown == null) {
|
|
200
|
-
// Native destinations can keep node metadata after dropping the
|
|
201
|
-
// Markdown wrapper and its definitions. Import their visible HTML.
|
|
202
|
-
for (const element of container.querySelectorAll('[data-inkkit-reference],[data-inkkit-footnote-reference],[data-inkkit-footnote-definition]')) {
|
|
203
|
-
for (const name of [
|
|
204
|
-
'data-inkkit-reference',
|
|
205
|
-
'data-inkkit-footnote-reference',
|
|
206
|
-
'data-inkkit-footnote-definition',
|
|
207
|
-
'data-inkkit-label',
|
|
208
|
-
'data-inkkit-reference-type',
|
|
209
|
-
'data-inkkit-reference-content',
|
|
210
|
-
])
|
|
211
|
-
element.removeAttribute(name);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// Native HTML clipboards add encoding metadata and fragment markers.
|
|
215
|
-
normalizeClipboardHTML(container);
|
|
216
|
-
// Obsidian's reading view also copies its title and collapse controls
|
|
217
|
-
// with document HTML.
|
|
218
|
-
for (const control of container.querySelectorAll('div.mod-header.mod-ui,div.mod-footer.mod-ui')) {
|
|
219
|
-
if (control.querySelector('.inline-title[contenteditable],.embedded-backlinks'))
|
|
220
|
-
control.remove();
|
|
221
|
-
}
|
|
222
|
-
for (const heading of container.querySelectorAll('h1[data-heading],h2[data-heading],h3[data-heading],h4[data-heading],h5[data-heading],h6[data-heading]')) {
|
|
223
|
-
for (const control of heading.querySelectorAll(':scope > span.heading-collapse-indicator.collapse-indicator.collapse-icon')) {
|
|
224
|
-
if (control.querySelector(':scope > svg.svg-icon.right-triangle') &&
|
|
225
|
-
!control.textContent?.trim())
|
|
226
|
-
control.remove();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
for (const control of container.querySelectorAll('pre > button.copy-code-button')) {
|
|
230
|
-
if (control.querySelector('svg.svg-icon'))
|
|
231
|
-
control.remove();
|
|
232
|
-
}
|
|
233
|
-
for (const element of [...container.querySelectorAll('*')]) {
|
|
234
|
-
if (!container.contains(element) || isRichElement(element))
|
|
235
|
-
continue;
|
|
236
|
-
const literal = document.createElement('pre');
|
|
237
|
-
literal.className = 'literal-markdown';
|
|
238
|
-
literal.textContent = element.outerHTML;
|
|
239
|
-
element.replaceWith(literal);
|
|
240
|
-
}
|
|
241
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_COMMENT);
|
|
242
|
-
const comments = [];
|
|
243
|
-
while (walker.nextNode())
|
|
244
|
-
comments.push(walker.currentNode);
|
|
245
|
-
for (const comment of comments) {
|
|
246
|
-
const literal = document.createElement('pre');
|
|
247
|
-
literal.className = 'literal-markdown';
|
|
248
|
-
literal.textContent = `<!--${comment.data}-->`;
|
|
249
|
-
comment.replaceWith(literal);
|
|
250
|
-
}
|
|
251
|
-
for (const table of [...container.querySelectorAll('table')]) {
|
|
252
|
-
if (table.parentElement?.closest('table'))
|
|
253
|
-
continue;
|
|
254
|
-
const rows = [...table.querySelectorAll('tr')];
|
|
255
|
-
const unsupported = !schema.nodes.table || unsupportedClipboardTable(table);
|
|
256
|
-
if (!unsupported && !table.querySelector('th')) {
|
|
257
|
-
for (const cell of rows[0]?.querySelectorAll(':scope > td') ?? []) {
|
|
258
|
-
const heading = document.createElement('th');
|
|
259
|
-
for (const attribute of [...cell.attributes])
|
|
260
|
-
heading.setAttribute(attribute.name, attribute.value);
|
|
261
|
-
heading.append(...cell.childNodes);
|
|
262
|
-
cell.replaceWith(heading);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (unsupported) {
|
|
266
|
-
const literal = document.createElement('pre');
|
|
267
|
-
literal.className = 'literal-markdown';
|
|
268
|
-
literal.textContent = table.outerHTML;
|
|
269
|
-
table.replaceWith(literal);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
collapseClipboardWhitespace(container);
|
|
273
|
-
const imported = new Map();
|
|
274
|
-
const elements = [...container.querySelectorAll('img')];
|
|
275
|
-
const uniqueSources = new Set(elements.map((element) => element.getAttribute('src') ?? ''));
|
|
276
|
-
// A host-supplied array explicitly associates unnamed bytes by unique
|
|
277
|
-
// preview order. A browser FileList has no such association, except the
|
|
278
|
-
// unambiguous single-file/single-source case.
|
|
279
|
-
const positional = (files.length === 0 || (files.length === 1 && uniqueSources.size === 1)
|
|
280
|
-
? images
|
|
281
|
-
: (input.images ?? [])).filter((image) => !image.source);
|
|
282
|
-
let index = 0;
|
|
283
|
-
for (const element of elements) {
|
|
284
|
-
const source = element.getAttribute('src') ?? '';
|
|
285
|
-
const alt = element.getAttribute('alt') ?? 'Image';
|
|
286
|
-
try {
|
|
287
|
-
let reference = imported.get(source);
|
|
288
|
-
if (!reference) {
|
|
289
|
-
const matched = images.find((image) => image.source ===
|
|
290
|
-
source);
|
|
291
|
-
const captured = matched ?? dataImage(source) ?? positional[index++];
|
|
292
|
-
if (!captured || !this.options.adapter)
|
|
293
|
-
throw new Error('The pasted image is unavailable.');
|
|
294
|
-
reference = (await this.options.adapter.importImage(captured, { ...context })).reference;
|
|
295
|
-
this.assertContext(context, operation);
|
|
296
|
-
imported.set(source, reference);
|
|
297
|
-
}
|
|
298
|
-
element.setAttribute('src', reference);
|
|
299
|
-
element.removeAttribute('srcset');
|
|
300
|
-
}
|
|
301
|
-
catch (error) {
|
|
302
|
-
if (error instanceof InkKitError)
|
|
303
|
-
throw error;
|
|
304
|
-
element.replaceWith(document.createTextNode(`[${alt}: image unavailable]`));
|
|
305
|
-
this.options.onError?.(new InkKitError('image-unavailable', error instanceof Error
|
|
306
|
-
? error.message
|
|
307
|
-
: 'The pasted image is unavailable.'));
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if (markdown != null) {
|
|
311
|
-
const parsed = ctx.get(parserCtx)(markdown);
|
|
312
|
-
let imageIndex = 0;
|
|
313
|
-
const hydrate = (node) => {
|
|
314
|
-
if (isImage(node)) {
|
|
315
|
-
const slot = /^inkkit-clipboard-image:(\d+)$/.exec(String(node.attrs.src));
|
|
316
|
-
const position = slot ? Number(slot[1]) : imageIndex++;
|
|
317
|
-
const element = elements.some((element) => element.hasAttribute('data-inkkit-image-slot'))
|
|
318
|
-
? elements.find((element) => Number(element.getAttribute('data-inkkit-authored-image-slot') ?? element.getAttribute('data-inkkit-image-slot')) === position)
|
|
319
|
-
: elements[position];
|
|
320
|
-
if (!element || !container.contains(element)) {
|
|
321
|
-
const text = schema.text(`[${node.attrs.alt || 'Image'}: image unavailable]`);
|
|
322
|
-
return node.isBlock
|
|
323
|
-
? schema.nodes.paragraph.create(null, text)
|
|
324
|
-
: text;
|
|
325
|
-
}
|
|
326
|
-
return node.type.create({ ...node.attrs, src: element.getAttribute('src') }, null, node.marks);
|
|
327
|
-
}
|
|
328
|
-
if (node.isText)
|
|
329
|
-
return node;
|
|
330
|
-
const children = [];
|
|
331
|
-
node.forEach((child) => children.push(hydrate(child)));
|
|
332
|
-
return node.copy(Fragment.fromArray(children));
|
|
333
|
-
};
|
|
334
|
-
slice = new Slice(hydrate(parsed).content, 0, 0);
|
|
335
|
-
}
|
|
336
|
-
else
|
|
337
|
-
slice = ProseParser.fromSchema(schema).parseSlice(container, {
|
|
338
|
-
preserveWhitespace: true,
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
else if (images.length) {
|
|
342
|
-
const nodes = [];
|
|
343
|
-
if (input.text)
|
|
344
|
-
nodes.push(schema.nodes.paragraph.create(null, schema.text(input.text)));
|
|
345
|
-
for (const image of images) {
|
|
346
|
-
try {
|
|
347
|
-
if (!this.options.adapter)
|
|
348
|
-
throw new InkKitError('image-unavailable', 'No image adapter is configured.');
|
|
349
|
-
const imported = await this.options.adapter.importImage(image, {
|
|
350
|
-
...context,
|
|
351
|
-
});
|
|
352
|
-
this.assertContext(context, operation);
|
|
353
|
-
const imageNode = schema.nodes.image?.create({
|
|
354
|
-
src: imported.reference,
|
|
355
|
-
alt: image.filename ?? 'Image',
|
|
356
|
-
});
|
|
357
|
-
if (!imageNode)
|
|
358
|
-
throw new InkKitError('image-unavailable', 'Images are disabled for this document.');
|
|
359
|
-
nodes.push(schema.nodes.paragraph.create(null, imageNode));
|
|
360
|
-
}
|
|
361
|
-
catch (error) {
|
|
362
|
-
if (error instanceof InkKitError &&
|
|
363
|
-
error.code !== 'image-unavailable')
|
|
364
|
-
throw error;
|
|
365
|
-
nodes.push(schema.nodes.paragraph.create(null, schema.text(`[${image.filename ?? 'Image'}: image unavailable]`)));
|
|
366
|
-
this.options.onError?.(new InkKitError('image-unavailable', error instanceof Error
|
|
367
|
-
? error.message
|
|
368
|
-
: 'The pasted image is unavailable.'));
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
slice = new Slice(Fragment.fromArray(nodes), 1, 1);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
const selection = view.state.selection;
|
|
375
|
-
const text = input.text.trim();
|
|
376
|
-
if (markdown == null &&
|
|
377
|
-
!selection.empty &&
|
|
378
|
-
/^https?:\/\/\S+$/.test(text) &&
|
|
379
|
-
schema.marks.link) {
|
|
380
|
-
const anchor = this.anchor(operation);
|
|
381
|
-
const mark = schema.marks.link.create({ href: text });
|
|
382
|
-
view.dispatch(view.state.tr
|
|
383
|
-
.addMark(anchor.from, anchor.to, mark)
|
|
384
|
-
.removeStoredMark(mark));
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
const doc = ctx.get(parserCtx)(markdown ?? input.text);
|
|
388
|
-
slice = new Slice(doc.content, 0, 0);
|
|
389
|
-
}
|
|
390
|
-
this.assertContext(context, operation);
|
|
391
|
-
if (!view.editable || this.options.editable?.() === false)
|
|
392
|
-
return;
|
|
393
|
-
const anchor = this.anchor(operation);
|
|
394
|
-
if (!plainText) {
|
|
395
|
-
const valid = slice.content.firstChild?.isInline
|
|
396
|
-
? Fragment.from(schema.nodes.paragraph.create(null, slice.content))
|
|
397
|
-
: slice.content;
|
|
398
|
-
const remapped = avoidReferenceCollisions(schema.topNodeType.create(null, valid), view.state.doc);
|
|
399
|
-
slice = new Slice(slice.content.firstChild?.isInline
|
|
400
|
-
? remapped.firstChild.content
|
|
401
|
-
: remapped.content, slice.openStart, slice.openEnd);
|
|
402
|
-
}
|
|
403
|
-
const insertion = view.state.doc.resolve(anchor.from);
|
|
404
|
-
// An isolated block such as a table cannot fit inside an empty paragraph.
|
|
405
|
-
// Replace that empty block rather than retaining a spurious spacer.
|
|
406
|
-
if (anchor.from === anchor.to &&
|
|
407
|
-
insertion.parent.type.name === 'paragraph' &&
|
|
408
|
-
insertion.parent.content.size === 0 &&
|
|
409
|
-
slice.content.firstChild?.isBlock &&
|
|
410
|
-
slice.content.firstChild.type.spec.isolating) {
|
|
411
|
-
view.dispatch(view.state.tr
|
|
412
|
-
.replaceRange(insertion.before(), insertion.after(), new Slice(slice.content, 0, 0))
|
|
413
|
-
.scrollIntoView());
|
|
414
|
-
}
|
|
415
|
-
else
|
|
416
|
-
view.dispatch(view.state.tr
|
|
417
|
-
.replaceRange(anchor.from, anchor.to, slice)
|
|
418
|
-
.scrollIntoView());
|
|
419
|
-
}
|
|
420
|
-
finally {
|
|
421
|
-
if (this.active === operation) {
|
|
422
|
-
this.active = undefined;
|
|
423
|
-
this.options.onPendingChanged?.();
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
function insideRewrittenContent(element) {
|
|
429
|
-
for (let parent = element.parentElement; parent; parent = parent.parentElement)
|
|
430
|
-
if (!isRewrittenElement(parent))
|
|
431
|
-
return false;
|
|
432
|
-
return true;
|
|
433
|
-
}
|
|
434
|
-
function unsupportedClipboardTable(table) {
|
|
435
|
-
const rows = [...table.querySelectorAll('tr')];
|
|
436
|
-
const widths = rows.map((row) => row.querySelectorAll(':scope > th,:scope > td').length);
|
|
437
|
-
const supported = new Set([
|
|
438
|
-
'THEAD',
|
|
439
|
-
'TBODY',
|
|
440
|
-
'TFOOT',
|
|
441
|
-
'TR',
|
|
442
|
-
'TH',
|
|
443
|
-
'TD',
|
|
444
|
-
'P',
|
|
445
|
-
'STRONG',
|
|
446
|
-
'B',
|
|
447
|
-
'EM',
|
|
448
|
-
'I',
|
|
449
|
-
'S',
|
|
450
|
-
'DEL',
|
|
451
|
-
'STRIKE',
|
|
452
|
-
'CODE',
|
|
453
|
-
'A',
|
|
454
|
-
'MARK',
|
|
455
|
-
'SPAN',
|
|
456
|
-
'SUP',
|
|
457
|
-
'FONT',
|
|
458
|
-
'IMG',
|
|
459
|
-
]);
|
|
460
|
-
return (widths.length === 0 ||
|
|
461
|
-
widths.some((width) => !width || width !== widths[0]) ||
|
|
462
|
-
!!document.createTreeWalker(table, NodeFilter.SHOW_COMMENT).nextNode() ||
|
|
463
|
-
[...table.querySelectorAll('*')].some((element) => !supported.has(element.tagName)) ||
|
|
464
|
-
[...table.querySelectorAll('p')].some((paragraph) => {
|
|
465
|
-
const cell = paragraph.parentElement;
|
|
466
|
-
return (!cell ||
|
|
467
|
-
!['TH', 'TD'].includes(cell.tagName) ||
|
|
468
|
-
cell.children.length !== 1 ||
|
|
469
|
-
[...cell.childNodes].some((node) => node !== paragraph && !!node.textContent?.trim()));
|
|
470
|
-
}) ||
|
|
471
|
-
!!table.querySelector('[rowspan]:not([rowspan="1"]),[colspan]:not([colspan="1"])'));
|
|
472
|
-
}
|
|
473
|
-
function dataImage(source) {
|
|
474
|
-
const match = /^data:(image\/(?:png|jpeg|gif|webp|avif|bmp|tiff));base64,([A-Za-z0-9+/=\s]+)$/.exec(source);
|
|
475
|
-
if (!match)
|
|
476
|
-
return undefined;
|
|
477
|
-
const binary = atob(match[2]);
|
|
478
|
-
return {
|
|
479
|
-
mimeType: match[1],
|
|
480
|
-
bytes: Uint8Array.from(binary, (character) => character.charCodeAt(0)),
|
|
481
|
-
};
|
|
482
|
-
}
|
package/dist/portable-files.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Node } from '@milkdown/kit/prose/model';
|
|
2
|
-
import type { DocumentContext, FileAdapter, FilePresentation, FileReference, ImageAdapter, PortableImage } from './types.js';
|
|
3
|
-
export interface PortableFile {
|
|
4
|
-
reference: FileReference;
|
|
5
|
-
presentation: FilePresentation;
|
|
6
|
-
label: string;
|
|
7
|
-
description: string;
|
|
8
|
-
}
|
|
9
|
-
export declare function portableFile(node: Node, adapter: FileAdapter | undefined, context: DocumentContext, signal: AbortSignal): Promise<PortableFile | undefined>;
|
|
10
|
-
export declare function portableFileImage(file: PortableFile, files: FileAdapter, legacy: ImageAdapter | undefined, context: DocumentContext, signal: AbortSignal): Promise<PortableImage>;
|
package/dist/portable-files.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { resolveFile, withFileSignal } from './files.js';
|
|
2
|
-
import { fileReference } from './linked-syntax.js';
|
|
3
|
-
export async function portableFile(node, adapter, context, signal) {
|
|
4
|
-
if (!adapter)
|
|
5
|
-
return undefined;
|
|
6
|
-
const reference = fileReference(node);
|
|
7
|
-
let presentation;
|
|
8
|
-
try {
|
|
9
|
-
presentation = await resolveFile(adapter, reference, { ...context, signal });
|
|
10
|
-
}
|
|
11
|
-
catch (error) {
|
|
12
|
-
signal.throwIfAborted();
|
|
13
|
-
presentation = {
|
|
14
|
-
kind: 'error',
|
|
15
|
-
message: error instanceof Error ? error.message : 'The file is unavailable.',
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
const label = presentation.label || reference.label || reference.reference || 'File';
|
|
19
|
-
const kind = presentation.kind;
|
|
20
|
-
const description = kind === 'missing' || kind === 'error'
|
|
21
|
-
? `[File: ${label} (${kind === 'missing' ? 'unavailable' : 'error'})]`
|
|
22
|
-
: `[${kind === 'pdf' ? 'PDF' : kind[0].toUpperCase() + kind.slice(1)}: ${label}]`;
|
|
23
|
-
return { reference, presentation, label, description };
|
|
24
|
-
}
|
|
25
|
-
export async function portableFileImage(file, files, legacy, context, signal) {
|
|
26
|
-
signal.throwIfAborted();
|
|
27
|
-
const image = files.exportImage
|
|
28
|
-
? await withFileSignal(files.exportImage(file.reference, { ...context, signal }), signal)
|
|
29
|
-
: file.reference.kind === 'path' && legacy
|
|
30
|
-
? await withFileSignal(legacy.exportImage(file.reference.reference, { ...context }), signal)
|
|
31
|
-
: undefined;
|
|
32
|
-
signal.throwIfAborted();
|
|
33
|
-
if (!image)
|
|
34
|
-
throw new Error('The image has no portable export adapter.');
|
|
35
|
-
return image;
|
|
36
|
-
}
|
package/dist/preserve.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Ctx } from '@milkdown/kit/ctx';
|
|
2
|
-
import type { Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
3
|
-
export declare class PreservationError extends Error {
|
|
4
|
-
constructor(message: string, options?: ErrorOptions);
|
|
5
|
-
}
|
|
6
|
-
export declare function correspondence(before: string[], after: string[], resemblance?: boolean): Array<number | undefined>;
|
|
7
|
-
/** Retains the loaded source of blocks the edit leaves alone. */
|
|
8
|
-
export declare class Preservation {
|
|
9
|
-
private readonly ctx;
|
|
10
|
-
private readonly source;
|
|
11
|
-
private readonly baseline;
|
|
12
|
-
private readonly blocks;
|
|
13
|
-
private readonly lineEnding;
|
|
14
|
-
private readonly originalForms;
|
|
15
|
-
private readonly forms;
|
|
16
|
-
private readonly textBlockEdits;
|
|
17
|
-
constructor(ctx: Ctx, source: string);
|
|
18
|
-
private retainBlock;
|
|
19
|
-
private independentTextBlocks;
|
|
20
|
-
serialize(doc: ProseNode): string;
|
|
21
|
-
}
|