@aicayzer/inkkit 0.0.18 → 0.1.1
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 +11 -7
- package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
- package/dist/chunks/core-CYp5ONPO.js +56519 -0
- package/dist/chunks/highlight-BW9W8PtS.js +14122 -0
- package/dist/core.d.ts +2 -5
- package/dist/core.js +2 -2
- package/dist/editor.d.ts +229 -47
- package/dist/index.js +5 -3
- package/dist/style.css +231 -202
- package/dist/types.d.ts +143 -18
- package/package.json +16 -13
- package/dist/autolink.d.ts +0 -1
- package/dist/autolink.js +0 -18
- package/dist/callouts.d.ts +0 -25
- package/dist/callouts.js +0 -288
- 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 -171
- package/dist/comments.d.ts +0 -76
- package/dist/comments.js +0 -545
- package/dist/cursor.d.ts +0 -2
- package/dist/cursor.js +0 -40
- 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 -446
- package/dist/drop-placement.d.ts +0 -19
- package/dist/drop-placement.js +0 -47
- package/dist/editor.js +0 -2673
- 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/html-import.d.ts +0 -13
- package/dist/html-import.js +0 -477
- package/dist/image-blocks.d.ts +0 -86
- package/dist/image-blocks.js +0 -329
- 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/link-safety.d.ts +0 -17
- package/dist/link-safety.js +0 -29
- package/dist/linked-syntax.d.ts +0 -48
- package/dist/linked-syntax.js +0 -320
- package/dist/literals.d.ts +0 -20
- package/dist/literals.js +0 -216
- package/dist/mermaid.d.ts +0 -28
- package/dist/mermaid.js +0 -404
- package/dist/outline.d.ts +0 -22
- package/dist/outline.js +0 -79
- package/dist/paste-html.d.ts +0 -31
- package/dist/paste-html.js +0 -462
- package/dist/paste.d.ts +0 -33
- package/dist/paste.js +0 -591
- package/dist/portable-files.d.ts +0 -10
- package/dist/portable-files.js +0 -36
- package/dist/preserve.d.ts +0 -38
- package/dist/preserve.js +0 -1396
- package/dist/print.d.ts +0 -7
- package/dist/print.js +0 -406
- package/dist/reference-clipboard.d.ts +0 -8
- package/dist/reference-clipboard.js +0 -201
- package/dist/references.d.ts +0 -16
- package/dist/references.js +0 -418
- package/dist/scroll.d.ts +0 -15
- package/dist/scroll.js +0 -27
- 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 -8
- package/dist/spreadsheet.js +0 -289
- 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 -344
- 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/references.js
DELETED
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
import { editorLabels } from './labels.js';
|
|
2
|
-
import { isSafeLinkTarget } from './link-safety.js';
|
|
3
|
-
import { $node, $remark, $prose } from '@milkdown/kit/utils';
|
|
4
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
5
|
-
import { linkSchema } from '@milkdown/kit/preset/commonmark';
|
|
6
|
-
import { normalizeIdentifier } from 'micromark-util-normalize-identifier';
|
|
7
|
-
import { gfmFootnote } from 'micromark-extension-gfm-footnote';
|
|
8
|
-
import { gfmFootnoteFromMarkdown, gfmFootnoteToMarkdown, } from 'mdast-util-gfm-footnote';
|
|
9
|
-
import { defaultHandlers } from 'mdast-util-to-markdown';
|
|
10
|
-
export function normaliseLabel(label) {
|
|
11
|
-
return normalizeIdentifier(label).toLowerCase();
|
|
12
|
-
}
|
|
13
|
-
function definitions(doc, type) {
|
|
14
|
-
const found = new Map();
|
|
15
|
-
doc.descendants((node, pos) => {
|
|
16
|
-
if (node.type.name !== type)
|
|
17
|
-
return true;
|
|
18
|
-
const identifier = normaliseLabel(String(node.attrs.identifier));
|
|
19
|
-
if (!found.has(identifier))
|
|
20
|
-
found.set(identifier, { node, pos });
|
|
21
|
-
return false;
|
|
22
|
-
});
|
|
23
|
-
return found;
|
|
24
|
-
}
|
|
25
|
-
export const referenceDefinitions = (doc) => definitions(doc, 'reference_definition');
|
|
26
|
-
export const footnoteDefinitions = (doc) => definitions(doc, 'footnote_definition');
|
|
27
|
-
function contentShape(value) {
|
|
28
|
-
const clean = (value) => {
|
|
29
|
-
if (Array.isArray(value))
|
|
30
|
-
return value.map(clean);
|
|
31
|
-
if (value && typeof value === 'object')
|
|
32
|
-
return Object.fromEntries(Object.entries(value)
|
|
33
|
-
.filter(([key]) => !['position', 'data', 'marker', 'isMark'].includes(key))
|
|
34
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
35
|
-
.map(([key, value]) => [key, clean(value)]));
|
|
36
|
-
return value;
|
|
37
|
-
};
|
|
38
|
-
return JSON.stringify(clean(value));
|
|
39
|
-
}
|
|
40
|
-
/** Replaces each line break, with the whitespace around it, by one space. */
|
|
41
|
-
export function singleLine(value) {
|
|
42
|
-
return value.replace(/[ \t]*[\r\n][ \t\r\n]*/g, ' ');
|
|
43
|
-
}
|
|
44
|
-
function nullableSingleLine(value) {
|
|
45
|
-
return value == null ? value : singleLine(value);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* A label is written as its authored text, so one that did not come from
|
|
49
|
-
* Markdown could close its brackets early or span lines. Line breaks become
|
|
50
|
-
* one space and an unescaped bracket is escaped. An authored label has no
|
|
51
|
-
* unescaped bracket, and source preservation keeps an unedited one as written.
|
|
52
|
-
*/
|
|
53
|
-
function writableLabel(label) {
|
|
54
|
-
const flat = singleLine(String(label));
|
|
55
|
-
let written = '';
|
|
56
|
-
for (let index = 0; index < flat.length; index++) {
|
|
57
|
-
const character = flat[index];
|
|
58
|
-
if (character === '\\') {
|
|
59
|
-
written += character;
|
|
60
|
-
if (index + 1 < flat.length)
|
|
61
|
-
written += flat[++index];
|
|
62
|
-
else
|
|
63
|
-
written += '\\';
|
|
64
|
-
}
|
|
65
|
-
else if (character === '[' || character === ']')
|
|
66
|
-
written += `\\${character}`;
|
|
67
|
-
else
|
|
68
|
-
written += character;
|
|
69
|
-
}
|
|
70
|
-
return written;
|
|
71
|
-
}
|
|
72
|
-
const labelPlaceholder = 'inkkit-authored-label';
|
|
73
|
-
const authoredLinkReference = (untyped, parent, state, info) => {
|
|
74
|
-
const node = untyped;
|
|
75
|
-
const full = defaultHandlers.linkReference({
|
|
76
|
-
...node,
|
|
77
|
-
label: labelPlaceholder,
|
|
78
|
-
identifier: labelPlaceholder,
|
|
79
|
-
referenceType: 'full',
|
|
80
|
-
}, parent, state, info);
|
|
81
|
-
const display = full.slice(1, -labelPlaceholder.length - 3);
|
|
82
|
-
const unchanged = node.referenceContent != null &&
|
|
83
|
-
node.referenceContent === contentShape(node.children);
|
|
84
|
-
if (node.referenceType !== 'full' &&
|
|
85
|
-
(unchanged || normaliseLabel(display) === normaliseLabel(node.identifier)))
|
|
86
|
-
return `[${unchanged ? writableLabel(node.label) : display}]${node.referenceType === 'collapsed' ? '[]' : ''}`;
|
|
87
|
-
// Raw entity and escape spelling participates in reference matching.
|
|
88
|
-
return (full.slice(0, -labelPlaceholder.length - 2) +
|
|
89
|
-
`[${writableLabel(node.label ?? node.identifier)}]`);
|
|
90
|
-
};
|
|
91
|
-
authoredLinkReference.peek = () => '[';
|
|
92
|
-
const authoredDefinition = (node, parent, state, info) => defaultHandlers
|
|
93
|
-
.definition({ ...node, label: labelPlaceholder, identifier: labelPlaceholder }, parent, state, info)
|
|
94
|
-
.replace(`[${labelPlaceholder}]:`, `[${writableLabel(node.label ?? node.identifier)}]:`);
|
|
95
|
-
const footnoteHandlers = gfmFootnoteToMarkdown().handlers;
|
|
96
|
-
const authoredFootnoteReference = (node) => `[^${writableLabel(node.label ?? node.identifier)}]`;
|
|
97
|
-
authoredFootnoteReference.peek = () => '[';
|
|
98
|
-
const authoredFootnoteDefinition = (node, parent, state, info) => footnoteHandlers.footnoteDefinition({ ...node, label: labelPlaceholder, identifier: labelPlaceholder }, parent, state, info).replace(`[^${labelPlaceholder}]:`, `[^${writableLabel(node.label ?? node.identifier)}]:`);
|
|
99
|
-
function remarkReferences() {
|
|
100
|
-
const data = this.data();
|
|
101
|
-
(data.micromarkExtensions ??= []).push(gfmFootnote());
|
|
102
|
-
(data.fromMarkdownExtensions ??= []).push(gfmFootnoteFromMarkdown());
|
|
103
|
-
(data.toMarkdownExtensions ??= []).push(gfmFootnoteToMarkdown());
|
|
104
|
-
(data.toMarkdownExtensions ??= []).push({
|
|
105
|
-
handlers: {
|
|
106
|
-
linkReference: authoredLinkReference,
|
|
107
|
-
definition: authoredDefinition,
|
|
108
|
-
footnoteReference: authoredFootnoteReference,
|
|
109
|
-
footnoteDefinition: authoredFootnoteDefinition,
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
return (tree, file) => {
|
|
113
|
-
const source = String(file.value).replace(/^\uFEFF/, '');
|
|
114
|
-
const targets = new Map();
|
|
115
|
-
const walk = (node, visit) => {
|
|
116
|
-
visit(node);
|
|
117
|
-
if ('children' in node)
|
|
118
|
-
node.children.forEach((child) => walk(child, visit));
|
|
119
|
-
};
|
|
120
|
-
walk(tree, (node) => {
|
|
121
|
-
const start = node.position?.start.offset;
|
|
122
|
-
const end = node.position?.end.offset;
|
|
123
|
-
if (start != null && end != null) {
|
|
124
|
-
const raw = source.slice(start, end);
|
|
125
|
-
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
|
|
126
|
-
const label = /^\[((?:\\[\s\S]|[^\\[\]])*)\]:/.exec(raw)?.[1];
|
|
127
|
-
if (label != null)
|
|
128
|
-
node.label =
|
|
129
|
-
node.type === 'footnoteDefinition' ? label.slice(1) : label;
|
|
130
|
-
}
|
|
131
|
-
else if (node.type === 'footnoteReference')
|
|
132
|
-
node.label = raw.slice(2, -1);
|
|
133
|
-
else if (node.type === 'linkReference') {
|
|
134
|
-
const label = node.referenceType === 'full'
|
|
135
|
-
? /\[((?:\\[\s\S]|[^\\[\]])*)\]$/.exec(raw)?.[1]
|
|
136
|
-
: raw.slice(1, node.referenceType === 'collapsed' ? -3 : -1);
|
|
137
|
-
if (label != null)
|
|
138
|
-
node.label = label;
|
|
139
|
-
Object.assign(node, { referenceContent: contentShape(node.children) });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (node.type === 'definition' && !targets.has(node.identifier))
|
|
143
|
-
targets.set(node.identifier, { url: node.url, title: node.title });
|
|
144
|
-
});
|
|
145
|
-
walk(tree, (node) => {
|
|
146
|
-
if (node.type !== 'linkReference')
|
|
147
|
-
return;
|
|
148
|
-
const target = targets.get(node.identifier);
|
|
149
|
-
if (target)
|
|
150
|
-
Object.assign(node, target);
|
|
151
|
-
});
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
export const remarkReferencesPlugin = $remark('inkkitReferences', () => remarkReferences);
|
|
155
|
-
export const referenceLinks = linkSchema.extendSchema((base) => (ctx) => {
|
|
156
|
-
const schema = base(ctx);
|
|
157
|
-
return {
|
|
158
|
-
...schema,
|
|
159
|
-
// Label formatting belongs inside a reference, where its source determines the identifier.
|
|
160
|
-
priority: 40,
|
|
161
|
-
attrs: {
|
|
162
|
-
...schema.attrs,
|
|
163
|
-
label: { default: null },
|
|
164
|
-
identifier: { default: null },
|
|
165
|
-
referenceType: { default: null },
|
|
166
|
-
referenceContent: { default: null },
|
|
167
|
-
},
|
|
168
|
-
parseDOM: [
|
|
169
|
-
{
|
|
170
|
-
tag: 'a[href]',
|
|
171
|
-
getAttrs(dom) {
|
|
172
|
-
const element = dom;
|
|
173
|
-
const href = element.getAttribute('href') ?? '';
|
|
174
|
-
// Imported HTML keeps the text of a link it cannot trust. Markdown
|
|
175
|
-
// source does not pass through here, so authored addresses stay.
|
|
176
|
-
if (!isSafeLinkTarget(href))
|
|
177
|
-
return false;
|
|
178
|
-
return {
|
|
179
|
-
href,
|
|
180
|
-
title: element.getAttribute('title'),
|
|
181
|
-
label: element.getAttribute('data-inkkit-label'),
|
|
182
|
-
identifier: element.getAttribute('data-inkkit-reference'),
|
|
183
|
-
referenceType: element.getAttribute('data-inkkit-reference-type'),
|
|
184
|
-
referenceContent: element.getAttribute('data-inkkit-reference-content'),
|
|
185
|
-
};
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
|
-
toDOM(mark) {
|
|
190
|
-
const dom = schema.toDOM(mark, false);
|
|
191
|
-
const attrs = { ...dom[1] };
|
|
192
|
-
delete attrs.label;
|
|
193
|
-
delete attrs.identifier;
|
|
194
|
-
delete attrs.referenceType;
|
|
195
|
-
delete attrs.referenceContent;
|
|
196
|
-
if (mark.attrs.identifier != null) {
|
|
197
|
-
attrs['data-inkkit-reference'] = mark.attrs.identifier;
|
|
198
|
-
attrs['data-inkkit-label'] = mark.attrs.label;
|
|
199
|
-
attrs['data-inkkit-reference-type'] = mark.attrs.referenceType;
|
|
200
|
-
attrs['data-inkkit-reference-content'] = mark.attrs.referenceContent;
|
|
201
|
-
}
|
|
202
|
-
return ['a', attrs];
|
|
203
|
-
},
|
|
204
|
-
parseMarkdown: {
|
|
205
|
-
match: (node) => node.type === 'link' || node.type === 'linkReference',
|
|
206
|
-
runner(state, node, type) {
|
|
207
|
-
if (node.type === 'link')
|
|
208
|
-
return schema.parseMarkdown.runner(state, node, type);
|
|
209
|
-
state.openMark(type, {
|
|
210
|
-
href: String(node.url ?? ''),
|
|
211
|
-
title: node.title ?? null,
|
|
212
|
-
label: String(node.label ?? node.identifier),
|
|
213
|
-
identifier: String(node.identifier),
|
|
214
|
-
referenceType: String(node.referenceType),
|
|
215
|
-
referenceContent: node.referenceContent ?? null,
|
|
216
|
-
});
|
|
217
|
-
state.next(node.children);
|
|
218
|
-
state.closeMark(type);
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
toMarkdown: {
|
|
222
|
-
...schema.toMarkdown,
|
|
223
|
-
runner(state, mark, node) {
|
|
224
|
-
if (mark.attrs.identifier == null)
|
|
225
|
-
return schema.toMarkdown.runner(state, mark, node);
|
|
226
|
-
state.withMark(mark, 'linkReference', undefined, {
|
|
227
|
-
identifier: mark.attrs.identifier,
|
|
228
|
-
label: mark.attrs.label,
|
|
229
|
-
referenceType: mark.attrs.referenceType,
|
|
230
|
-
referenceContent: mark.attrs.referenceContent,
|
|
231
|
-
});
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
};
|
|
235
|
-
});
|
|
236
|
-
const associationAttrs = {
|
|
237
|
-
label: { default: '' },
|
|
238
|
-
identifier: { default: '' },
|
|
239
|
-
};
|
|
240
|
-
export const referenceDefinition = $node('reference_definition', () => ({
|
|
241
|
-
group: 'block',
|
|
242
|
-
atom: true,
|
|
243
|
-
defining: true,
|
|
244
|
-
attrs: {
|
|
245
|
-
...associationAttrs,
|
|
246
|
-
url: { default: '' },
|
|
247
|
-
title: { default: null },
|
|
248
|
-
},
|
|
249
|
-
parseDOM: [
|
|
250
|
-
{
|
|
251
|
-
tag: '[data-inkkit-reference-definition]',
|
|
252
|
-
getAttrs(dom) {
|
|
253
|
-
const url = dom.getAttribute('data-inkkit-url') ?? '';
|
|
254
|
-
if (!isSafeLinkTarget(url))
|
|
255
|
-
return false;
|
|
256
|
-
return {
|
|
257
|
-
label: dom.getAttribute('data-inkkit-label') ?? '',
|
|
258
|
-
identifier: dom.getAttribute('data-inkkit-reference-definition') ?? '',
|
|
259
|
-
url,
|
|
260
|
-
// Saved on one line, as the writer would save it.
|
|
261
|
-
title: nullableSingleLine(dom.getAttribute('data-inkkit-title')),
|
|
262
|
-
};
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
toDOM: (node) => [
|
|
267
|
-
'div',
|
|
268
|
-
{
|
|
269
|
-
class: 'inkkit-reference-definition',
|
|
270
|
-
'data-inkkit-reference-definition': node.attrs.identifier,
|
|
271
|
-
'data-inkkit-label': node.attrs.label,
|
|
272
|
-
'data-inkkit-url': node.attrs.url,
|
|
273
|
-
'data-inkkit-title': node.attrs.title,
|
|
274
|
-
},
|
|
275
|
-
`[${node.attrs.label}]: ${node.attrs.url}${node.attrs.title ? ` "${node.attrs.title}"` : ''}`,
|
|
276
|
-
],
|
|
277
|
-
parseMarkdown: {
|
|
278
|
-
match: (node) => node.type === 'definition',
|
|
279
|
-
runner(state, node, type) {
|
|
280
|
-
state.addNode(type, {
|
|
281
|
-
label: String(node.label ?? node.identifier),
|
|
282
|
-
identifier: String(node.identifier),
|
|
283
|
-
url: String(node.url),
|
|
284
|
-
title: node.title ?? null,
|
|
285
|
-
});
|
|
286
|
-
},
|
|
287
|
-
},
|
|
288
|
-
toMarkdown: {
|
|
289
|
-
match: (node) => node.type.name === 'reference_definition',
|
|
290
|
-
runner: (state, node) => {
|
|
291
|
-
// A line break in a definition title is written as it is, and a blank
|
|
292
|
-
// line would end the definition.
|
|
293
|
-
const title = node.attrs.title;
|
|
294
|
-
state.addNode('definition', undefined, undefined, {
|
|
295
|
-
...node.attrs,
|
|
296
|
-
title: typeof title === 'string' ? singleLine(title) : title,
|
|
297
|
-
});
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
}));
|
|
301
|
-
export const footnoteReference = $node('footnote_reference', (ctx) => ({
|
|
302
|
-
inline: true,
|
|
303
|
-
group: 'inline',
|
|
304
|
-
atom: true,
|
|
305
|
-
selectable: true,
|
|
306
|
-
attrs: associationAttrs,
|
|
307
|
-
parseDOM: [
|
|
308
|
-
{
|
|
309
|
-
tag: 'sup[data-inkkit-footnote-reference]',
|
|
310
|
-
getAttrs: (dom) => ({
|
|
311
|
-
label: dom.getAttribute('data-inkkit-label') ?? '',
|
|
312
|
-
identifier: dom.getAttribute('data-inkkit-footnote-reference') ?? '',
|
|
313
|
-
}),
|
|
314
|
-
},
|
|
315
|
-
],
|
|
316
|
-
toDOM: (node) => [
|
|
317
|
-
'sup',
|
|
318
|
-
{
|
|
319
|
-
class: 'inkkit-footnote-reference',
|
|
320
|
-
tabindex: '0',
|
|
321
|
-
role: 'button',
|
|
322
|
-
'aria-label': `${editorLabels(ctx).footnote} ${node.attrs.label}`,
|
|
323
|
-
'data-inkkit-footnote-reference': node.attrs.identifier,
|
|
324
|
-
'data-inkkit-label': node.attrs.label,
|
|
325
|
-
},
|
|
326
|
-
String(node.attrs.label),
|
|
327
|
-
],
|
|
328
|
-
parseMarkdown: {
|
|
329
|
-
match: (node) => node.type === 'footnoteReference',
|
|
330
|
-
runner(state, node, type) {
|
|
331
|
-
state.addNode(type, {
|
|
332
|
-
label: String(node.label ?? node.identifier),
|
|
333
|
-
identifier: String(node.identifier),
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
toMarkdown: {
|
|
338
|
-
match: (node) => node.type.name === 'footnote_reference',
|
|
339
|
-
runner: (state, node) => {
|
|
340
|
-
state.addNode('footnoteReference', undefined, undefined, {
|
|
341
|
-
...node.attrs,
|
|
342
|
-
});
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
}));
|
|
346
|
-
export const footnoteDefinition = $node('footnote_definition', (ctx) => ({
|
|
347
|
-
group: 'block',
|
|
348
|
-
content: 'block+',
|
|
349
|
-
defining: true,
|
|
350
|
-
attrs: associationAttrs,
|
|
351
|
-
parseDOM: [
|
|
352
|
-
{
|
|
353
|
-
tag: '[data-inkkit-footnote-definition]',
|
|
354
|
-
getAttrs: (dom) => ({
|
|
355
|
-
label: dom.getAttribute('data-inkkit-label') ?? '',
|
|
356
|
-
identifier: dom.getAttribute('data-inkkit-footnote-definition') ?? '',
|
|
357
|
-
}),
|
|
358
|
-
},
|
|
359
|
-
],
|
|
360
|
-
toDOM: (node) => [
|
|
361
|
-
'div',
|
|
362
|
-
{
|
|
363
|
-
class: 'inkkit-footnote-definition',
|
|
364
|
-
'aria-label': `${editorLabels(ctx).footnote} ${node.attrs.label}`,
|
|
365
|
-
'data-inkkit-footnote-definition': node.attrs.identifier,
|
|
366
|
-
'data-inkkit-label': node.attrs.label,
|
|
367
|
-
},
|
|
368
|
-
0,
|
|
369
|
-
],
|
|
370
|
-
parseMarkdown: {
|
|
371
|
-
match: (node) => node.type === 'footnoteDefinition',
|
|
372
|
-
runner(state, node, type) {
|
|
373
|
-
state.openNode(type, {
|
|
374
|
-
label: String(node.label ?? node.identifier),
|
|
375
|
-
identifier: String(node.identifier),
|
|
376
|
-
});
|
|
377
|
-
state.next(node.children);
|
|
378
|
-
state.closeNode();
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
toMarkdown: {
|
|
382
|
-
match: (node) => node.type.name === 'footnote_definition',
|
|
383
|
-
runner(state, node) {
|
|
384
|
-
state.openNode('footnoteDefinition', undefined, { ...node.attrs });
|
|
385
|
-
state.next(node.content);
|
|
386
|
-
state.closeNode();
|
|
387
|
-
},
|
|
388
|
-
},
|
|
389
|
-
}));
|
|
390
|
-
const resolvedReferenceTargets = $prose(() => new Plugin({
|
|
391
|
-
key: new PluginKey('inkkitReferenceTargets'),
|
|
392
|
-
appendTransaction(transactions, _before, state) {
|
|
393
|
-
if (!transactions.some((transaction) => transaction.docChanged))
|
|
394
|
-
return null;
|
|
395
|
-
const targets = referenceDefinitions(state.doc);
|
|
396
|
-
const tr = state.tr;
|
|
397
|
-
state.doc.descendants((node, pos) => {
|
|
398
|
-
for (const mark of node.marks) {
|
|
399
|
-
if (mark.type.name !== 'link' || mark.attrs.identifier == null)
|
|
400
|
-
continue;
|
|
401
|
-
const target = targets.get(normaliseLabel(String(mark.attrs.identifier)))?.node;
|
|
402
|
-
const href = String(target?.attrs.url ?? '');
|
|
403
|
-
const title = target?.attrs.title ?? null;
|
|
404
|
-
if (mark.attrs.href === href && mark.attrs.title === title)
|
|
405
|
-
continue;
|
|
406
|
-
tr.addMark(pos, pos + node.nodeSize, mark.type.create({ ...mark.attrs, href, title }));
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
return tr.docChanged ? tr.setMeta('addToHistory', false) : null;
|
|
410
|
-
},
|
|
411
|
-
}));
|
|
412
|
-
export const references = [
|
|
413
|
-
referenceLinks,
|
|
414
|
-
referenceDefinition,
|
|
415
|
-
footnoteReference,
|
|
416
|
-
footnoteDefinition,
|
|
417
|
-
resolvedReferenceTargets,
|
|
418
|
-
].flat();
|
package/dist/scroll.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/** Rounds a distance away from zero, to a whole number of pixels. */
|
|
2
|
-
export declare const scrollOutward: (distance: number) => number;
|
|
3
|
-
/**
|
|
4
|
-
* Scrolls an element by a distance and returns what it did not scroll. A
|
|
5
|
-
* scroll position is a whole number of pixels in some engines, so a fraction
|
|
6
|
-
* is rounded away from zero: rounded to nothing, a reveal would leave the last
|
|
7
|
-
* fraction of the target outside the element.
|
|
8
|
-
*/
|
|
9
|
-
export declare function scrollWholePixels(element: HTMLElement, vertical: number, horizontal: number, padding?: {
|
|
10
|
-
top: number;
|
|
11
|
-
bottom: number;
|
|
12
|
-
}): {
|
|
13
|
-
vertical: number;
|
|
14
|
-
horizontal: number;
|
|
15
|
-
};
|
package/dist/scroll.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/** Rounds a distance away from zero, to a whole number of pixels. */
|
|
2
|
-
export const scrollOutward = (distance) => distance > 0 ? Math.ceil(distance) : Math.floor(distance);
|
|
3
|
-
/**
|
|
4
|
-
* Scrolls an element by a distance and returns what it did not scroll. A
|
|
5
|
-
* scroll position is a whole number of pixels in some engines, so a fraction
|
|
6
|
-
* is rounded away from zero: rounded to nothing, a reveal would leave the last
|
|
7
|
-
* fraction of the target outside the element.
|
|
8
|
-
*/
|
|
9
|
-
export function scrollWholePixels(element, vertical, horizontal, padding = { top: 0, bottom: 0 }) {
|
|
10
|
-
const top = element.scrollTop, left = element.scrollLeft;
|
|
11
|
-
const target = top + scrollOutward(vertical);
|
|
12
|
-
const last = element.scrollHeight - element.clientHeight;
|
|
13
|
-
// Only padding is left beyond the target, so show it: a reveal that stops
|
|
14
|
-
// at the first or last line would otherwise hide that padding.
|
|
15
|
-
element.scrollTop =
|
|
16
|
-
vertical < 0 && target <= padding.top
|
|
17
|
-
? 0
|
|
18
|
-
: vertical > 0 && last > 0 && target >= last - padding.bottom
|
|
19
|
-
? last
|
|
20
|
-
: target;
|
|
21
|
-
element.scrollLeft += scrollOutward(horizontal);
|
|
22
|
-
const remaining = (distance, moved) => distance > 0 ? Math.max(0, distance - moved) : Math.min(0, distance - moved);
|
|
23
|
-
return {
|
|
24
|
-
vertical: remaining(vertical, element.scrollTop - top),
|
|
25
|
-
horizontal: remaining(horizontal, element.scrollLeft - left),
|
|
26
|
-
};
|
|
27
|
-
}
|
package/dist/search.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type Transaction } from '@milkdown/kit/prose/state';
|
|
2
|
-
import type { EditorView } from '@milkdown/kit/prose/view';
|
|
3
|
-
export interface TextMatch {
|
|
4
|
-
from: number;
|
|
5
|
-
to: number;
|
|
6
|
-
}
|
|
7
|
-
export interface LiteralReplacement extends TextMatch {
|
|
8
|
-
text: string;
|
|
9
|
-
count: number;
|
|
10
|
-
}
|
|
11
|
-
export declare function findLiteral(text: string, search: string, from?: number): TextMatch | undefined;
|
|
12
|
-
export declare function replaceLiteral(text: string, search: string, replacement: string, selection: TextMatch, all?: boolean): LiteralReplacement;
|
|
13
|
-
export declare function findFormatted(view: EditorView, text: string): boolean;
|
|
14
|
-
export declare function replaceFormatted(view: EditorView, search: string, replacement: string, preflight: (tr: Transaction) => void, all?: boolean): number;
|
|
15
|
-
export declare function replaceFormattedRange(view: EditorView, from: number, to: number, replacement: string, preflight: (tr: Transaction) => void): boolean;
|
package/dist/search.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { Fragment, Slice } from '@milkdown/kit/prose/model';
|
|
2
|
-
import { closeHistory } from '@milkdown/kit/prose/history';
|
|
3
|
-
import { Selection, TextSelection, } from '@milkdown/kit/prose/state';
|
|
4
|
-
import { SearchQuery, setSearchState, getSearchState } from 'prosemirror-search';
|
|
5
|
-
import { InkKitError } from './types.js';
|
|
6
|
-
function escapedPattern(text) {
|
|
7
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
8
|
-
}
|
|
9
|
-
function literalMatches(text, search) {
|
|
10
|
-
if (!search)
|
|
11
|
-
return [];
|
|
12
|
-
const pattern = new RegExp(escapedPattern(search), 'giu');
|
|
13
|
-
return [...text.matchAll(pattern)].map((match) => ({
|
|
14
|
-
from: match.index,
|
|
15
|
-
to: match.index + match[0].length,
|
|
16
|
-
}));
|
|
17
|
-
}
|
|
18
|
-
export function findLiteral(text, search, from = 0) {
|
|
19
|
-
const matches = literalMatches(text, search);
|
|
20
|
-
return matches.find((match) => match.from >= from) ?? matches[0];
|
|
21
|
-
}
|
|
22
|
-
export function replaceLiteral(text, search, replacement, selection, all = false) {
|
|
23
|
-
const matches = literalMatches(text, search);
|
|
24
|
-
const selected = matches.find((match) => match.from === selection.from && match.to === selection.to) ??
|
|
25
|
-
matches.find((match) => match.from >= selection.to) ??
|
|
26
|
-
matches[0];
|
|
27
|
-
const changed = (all ? matches : selected ? [selected] : []).filter((match) => text.slice(match.from, match.to) !== replacement);
|
|
28
|
-
if (!changed.length)
|
|
29
|
-
return { ...selection, text, count: 0 };
|
|
30
|
-
let output = text;
|
|
31
|
-
for (const match of [...changed].reverse())
|
|
32
|
-
output = output.slice(0, match.from) + replacement + output.slice(match.to);
|
|
33
|
-
if (!all)
|
|
34
|
-
return {
|
|
35
|
-
text: output,
|
|
36
|
-
count: 1,
|
|
37
|
-
from: changed[0].from,
|
|
38
|
-
to: changed[0].from + replacement.length,
|
|
39
|
-
};
|
|
40
|
-
const map = (position) => {
|
|
41
|
-
let difference = 0;
|
|
42
|
-
for (const match of changed) {
|
|
43
|
-
if (position < match.from)
|
|
44
|
-
break;
|
|
45
|
-
if (position <= match.to)
|
|
46
|
-
return (match.from +
|
|
47
|
-
difference +
|
|
48
|
-
(position === match.from ? 0 : replacement.length));
|
|
49
|
-
difference += replacement.length - (match.to - match.from);
|
|
50
|
-
}
|
|
51
|
-
return position + difference;
|
|
52
|
-
};
|
|
53
|
-
return {
|
|
54
|
-
text: output,
|
|
55
|
-
count: changed.length,
|
|
56
|
-
from: map(selection.from),
|
|
57
|
-
to: map(selection.to),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function formattedQuery(text) {
|
|
61
|
-
// Unicode regexp matching retains offsets when lowercasing would expand a character.
|
|
62
|
-
return new SearchQuery({
|
|
63
|
-
search: escapedPattern(text),
|
|
64
|
-
regexp: true,
|
|
65
|
-
literal: true,
|
|
66
|
-
filter: (state, match) => {
|
|
67
|
-
const from = state.doc.resolve(match.from);
|
|
68
|
-
const to = state.doc.resolve(match.to);
|
|
69
|
-
if (from.parent !== to.parent || !from.parent.inlineContent)
|
|
70
|
-
return false;
|
|
71
|
-
const content = state.doc.slice(match.from, match.to).content;
|
|
72
|
-
let textOnly = true;
|
|
73
|
-
content.forEach((node) => {
|
|
74
|
-
if (!node.isText)
|
|
75
|
-
textOnly = false;
|
|
76
|
-
});
|
|
77
|
-
return textOnly;
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
export function findFormatted(view, text) {
|
|
82
|
-
const query = formattedQuery(text);
|
|
83
|
-
const previous = getSearchState(view.state)?.query.search;
|
|
84
|
-
let tr = setSearchState(view.state.tr, query);
|
|
85
|
-
let found = false;
|
|
86
|
-
if (text) {
|
|
87
|
-
const start = previous === query.search
|
|
88
|
-
? view.state.selection.to
|
|
89
|
-
: view.state.selection.from;
|
|
90
|
-
const match = query.findNext(view.state, start) ?? query.findNext(view.state, 0);
|
|
91
|
-
if (match) {
|
|
92
|
-
found = true;
|
|
93
|
-
tr = tr
|
|
94
|
-
.setSelection(TextSelection.create(tr.doc, match.from, match.to))
|
|
95
|
-
.scrollIntoView();
|
|
96
|
-
}
|
|
97
|
-
else
|
|
98
|
-
tr = tr.setSelection(Selection.near(view.state.selection.$to));
|
|
99
|
-
}
|
|
100
|
-
else if (previous)
|
|
101
|
-
tr = tr.setSelection(Selection.near(view.state.selection.$to));
|
|
102
|
-
view.dispatch(tr);
|
|
103
|
-
return found;
|
|
104
|
-
}
|
|
105
|
-
function replacementSlice(state, from, to, value) {
|
|
106
|
-
const start = state.doc.resolve(from), end = state.doc.resolve(to);
|
|
107
|
-
const marks = start.marksAcross(end) ?? start.marks();
|
|
108
|
-
const nodes = [];
|
|
109
|
-
if (start.parent.type.spec.code) {
|
|
110
|
-
if (value)
|
|
111
|
-
nodes.push(state.schema.text(value, marks));
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
const lines = value.split('\n');
|
|
115
|
-
lines.forEach((line, index) => {
|
|
116
|
-
if (index)
|
|
117
|
-
nodes.push(state.schema.nodes.hardbreak.create({ isHTML: index === lines.length - 1 && line === '' }, null, marks));
|
|
118
|
-
if (line)
|
|
119
|
-
nodes.push(state.schema.text(line, marks));
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return new Slice(Fragment.fromArray(nodes), 0, 0);
|
|
123
|
-
}
|
|
124
|
-
export function replaceFormatted(view, search, replacement, preflight, all = false) {
|
|
125
|
-
if (!search)
|
|
126
|
-
return 0;
|
|
127
|
-
const state = view.state;
|
|
128
|
-
const query = formattedQuery(search);
|
|
129
|
-
if (!query.valid)
|
|
130
|
-
return 0;
|
|
131
|
-
const matches = [];
|
|
132
|
-
if (all) {
|
|
133
|
-
for (let position = 0;;) {
|
|
134
|
-
const match = query.findNext(state, position);
|
|
135
|
-
if (!match)
|
|
136
|
-
break;
|
|
137
|
-
matches.push(match);
|
|
138
|
-
position = match.to;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
const selection = state.selection;
|
|
143
|
-
const current = query.findNext(state, selection.from, selection.to);
|
|
144
|
-
const match = (current?.from === selection.from && current.to === selection.to
|
|
145
|
-
? current
|
|
146
|
-
: undefined) ??
|
|
147
|
-
query.findNext(state, selection.to) ??
|
|
148
|
-
query.findNext(state, 0);
|
|
149
|
-
if (match)
|
|
150
|
-
matches.push(match);
|
|
151
|
-
}
|
|
152
|
-
const value = replacement.replace(/\r\n?/g, '\n');
|
|
153
|
-
const changed = matches.filter((match) => state.doc.textBetween(match.from, match.to) !== value);
|
|
154
|
-
if (!changed.length)
|
|
155
|
-
return 0;
|
|
156
|
-
let tr = setSearchState(state.tr, query);
|
|
157
|
-
for (const match of [...changed].reverse()) {
|
|
158
|
-
tr.replace(match.from, match.to, replacementSlice(state, match.from, match.to, value));
|
|
159
|
-
}
|
|
160
|
-
if (!all) {
|
|
161
|
-
const match = changed[0];
|
|
162
|
-
tr = tr.setSelection(TextSelection.create(tr.doc, match.from, tr.mapping.map(match.to, 1)));
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
preflight(tr);
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
if (error instanceof InkKitError)
|
|
169
|
-
throw error;
|
|
170
|
-
throw new InkKitError('preservation', error instanceof Error ? error.message : 'Cannot preserve replacement');
|
|
171
|
-
}
|
|
172
|
-
view.dispatch(closeHistory(tr).scrollIntoView());
|
|
173
|
-
view.dispatch(closeHistory(view.state.tr).setMeta('addToHistory', false));
|
|
174
|
-
return changed.length;
|
|
175
|
-
}
|
|
176
|
-
export function replaceFormattedRange(view, from, to, replacement, preflight) {
|
|
177
|
-
const start = view.state.doc.resolve(from);
|
|
178
|
-
const end = view.state.doc.resolve(to);
|
|
179
|
-
let textOnly = start.parent === end.parent && start.parent.inlineContent;
|
|
180
|
-
view.state.doc.nodesBetween(from, to, (node) => {
|
|
181
|
-
if (!node.isText && !node.isTextblock)
|
|
182
|
-
textOnly = false;
|
|
183
|
-
});
|
|
184
|
-
if (!textOnly)
|
|
185
|
-
throw new InkKitError('invalid-range', 'Replacement requires literal text within one block');
|
|
186
|
-
const value = replacement.replace(/\r\n?/g, '\n');
|
|
187
|
-
if (view.state.doc.textBetween(from, to) === value)
|
|
188
|
-
return false;
|
|
189
|
-
const tr = closeHistory(view.state.tr.replace(from, to, replacementSlice(view.state, from, to, value)));
|
|
190
|
-
tr.setSelection(TextSelection.create(tr.doc, from, tr.mapping.map(to, 1)));
|
|
191
|
-
try {
|
|
192
|
-
preflight(tr);
|
|
193
|
-
}
|
|
194
|
-
catch (error) {
|
|
195
|
-
if (error instanceof InkKitError)
|
|
196
|
-
throw error;
|
|
197
|
-
throw new InkKitError('preservation', error instanceof Error ? error.message : 'Cannot preserve replacement');
|
|
198
|
-
}
|
|
199
|
-
view.dispatch(tr);
|
|
200
|
-
view.dispatch(closeHistory(view.state.tr).setMeta('addToHistory', false));
|
|
201
|
-
return true;
|
|
202
|
-
}
|
package/dist/selection.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const selectionPlugin: import("@milkdown/kit/utils").$Prose;
|