@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.
Files changed (90) hide show
  1. package/NOTICE +4 -2
  2. package/README.md +11 -7
  3. package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
  4. package/dist/chunks/core-CYp5ONPO.js +56519 -0
  5. package/dist/chunks/highlight-BW9W8PtS.js +14122 -0
  6. package/dist/core.d.ts +2 -5
  7. package/dist/core.js +2 -2
  8. package/dist/editor.d.ts +229 -47
  9. package/dist/index.js +5 -3
  10. package/dist/style.css +231 -202
  11. package/dist/types.d.ts +143 -18
  12. package/package.json +16 -13
  13. package/dist/autolink.d.ts +0 -1
  14. package/dist/autolink.js +0 -18
  15. package/dist/callouts.d.ts +0 -25
  16. package/dist/callouts.js +0 -288
  17. package/dist/clipboard.d.ts +0 -11
  18. package/dist/clipboard.js +0 -261
  19. package/dist/code-fences.d.ts +0 -8
  20. package/dist/code-fences.js +0 -171
  21. package/dist/comments.d.ts +0 -76
  22. package/dist/comments.js +0 -545
  23. package/dist/cursor.d.ts +0 -2
  24. package/dist/cursor.js +0 -40
  25. package/dist/decorations.d.ts +0 -2
  26. package/dist/decorations.js +0 -67
  27. package/dist/dialect.d.ts +0 -9
  28. package/dist/dialect.js +0 -446
  29. package/dist/drop-placement.d.ts +0 -19
  30. package/dist/drop-placement.js +0 -47
  31. package/dist/editor.js +0 -2673
  32. package/dist/files.d.ts +0 -40
  33. package/dist/files.js +0 -133
  34. package/dist/highlight.d.ts +0 -1
  35. package/dist/highlight.js +0 -136
  36. package/dist/html-import.d.ts +0 -13
  37. package/dist/html-import.js +0 -477
  38. package/dist/image-blocks.d.ts +0 -86
  39. package/dist/image-blocks.js +0 -329
  40. package/dist/images.d.ts +0 -51
  41. package/dist/images.js +0 -398
  42. package/dist/inline-highlight.d.ts +0 -6
  43. package/dist/inline-highlight.js +0 -112
  44. package/dist/labels.d.ts +0 -36
  45. package/dist/labels.js +0 -34
  46. package/dist/link-safety.d.ts +0 -17
  47. package/dist/link-safety.js +0 -29
  48. package/dist/linked-syntax.d.ts +0 -48
  49. package/dist/linked-syntax.js +0 -320
  50. package/dist/literals.d.ts +0 -20
  51. package/dist/literals.js +0 -216
  52. package/dist/mermaid.d.ts +0 -28
  53. package/dist/mermaid.js +0 -404
  54. package/dist/outline.d.ts +0 -22
  55. package/dist/outline.js +0 -79
  56. package/dist/paste-html.d.ts +0 -31
  57. package/dist/paste-html.js +0 -462
  58. package/dist/paste.d.ts +0 -33
  59. package/dist/paste.js +0 -591
  60. package/dist/portable-files.d.ts +0 -10
  61. package/dist/portable-files.js +0 -36
  62. package/dist/preserve.d.ts +0 -38
  63. package/dist/preserve.js +0 -1396
  64. package/dist/print.d.ts +0 -7
  65. package/dist/print.js +0 -406
  66. package/dist/reference-clipboard.d.ts +0 -8
  67. package/dist/reference-clipboard.js +0 -201
  68. package/dist/references.d.ts +0 -16
  69. package/dist/references.js +0 -418
  70. package/dist/scroll.d.ts +0 -15
  71. package/dist/scroll.js +0 -27
  72. package/dist/search.d.ts +0 -15
  73. package/dist/search.js +0 -202
  74. package/dist/selection.d.ts +0 -1
  75. package/dist/selection.js +0 -59
  76. package/dist/source.d.ts +0 -16
  77. package/dist/source.js +0 -57
  78. package/dist/spreadsheet.d.ts +0 -8
  79. package/dist/spreadsheet.js +0 -289
  80. package/dist/table-alignment.d.ts +0 -2
  81. package/dist/table-alignment.js +0 -46
  82. package/dist/tables.d.ts +0 -27
  83. package/dist/tables.js +0 -344
  84. package/dist/tasks.d.ts +0 -3
  85. package/dist/tasks.js +0 -51
  86. package/dist/text-ranges.d.ts +0 -29
  87. package/dist/text-ranges.js +0 -256
  88. package/dist/types.js +0 -8
  89. package/dist/wiki-view.d.ts +0 -21
  90. package/dist/wiki-view.js +0 -78
@@ -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
- }
@@ -1 +0,0 @@
1
- export declare const selectionPlugin: import("@milkdown/kit/utils").$Prose;