@aicayzer/inkkit 0.0.8 → 0.0.10

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/dist/search.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Fragment, Slice } from '@milkdown/kit/prose/model';
2
2
  import { closeHistory } from '@milkdown/kit/prose/history';
3
- import { Selection, TextSelection } from '@milkdown/kit/prose/state';
3
+ import { Selection, TextSelection, } from '@milkdown/kit/prose/state';
4
4
  import { SearchQuery, setSearchState, getSearchState } from 'prosemirror-search';
5
5
  import { InkKitError } from './types.js';
6
6
  function escapedPattern(text) {
@@ -82,21 +82,44 @@ export function findFormatted(view, text) {
82
82
  const query = formattedQuery(text);
83
83
  const previous = getSearchState(view.state)?.query.search;
84
84
  let tr = setSearchState(view.state.tr, query);
85
+ let found = false;
85
86
  if (text) {
86
87
  const start = previous === query.search
87
88
  ? view.state.selection.to
88
89
  : view.state.selection.from;
89
90
  const match = query.findNext(view.state, start) ?? query.findNext(view.state, 0);
90
- if (match)
91
+ if (match) {
92
+ found = true;
91
93
  tr = tr
92
94
  .setSelection(TextSelection.create(tr.doc, match.from, match.to))
93
95
  .scrollIntoView();
96
+ }
94
97
  else
95
98
  tr = tr.setSelection(Selection.near(view.state.selection.$to));
96
99
  }
97
100
  else if (previous)
98
101
  tr = tr.setSelection(Selection.near(view.state.selection.$to));
99
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);
100
123
  }
101
124
  export function replaceFormatted(view, search, replacement, preflight, all = false) {
102
125
  if (!search)
@@ -132,26 +155,7 @@ export function replaceFormatted(view, search, replacement, preflight, all = fal
132
155
  return 0;
133
156
  let tr = setSearchState(state.tr, query);
134
157
  for (const match of [...changed].reverse()) {
135
- const from = state.doc.resolve(match.from);
136
- const to = state.doc.resolve(match.to);
137
- const marks = from.marksAcross(to) ?? from.marks();
138
- let content = Fragment.empty;
139
- if (from.parent.type.spec.code) {
140
- if (value)
141
- content = Fragment.from(state.schema.text(value, marks));
142
- }
143
- else {
144
- const nodes = [];
145
- const lines = value.split('\n');
146
- lines.forEach((line, index) => {
147
- if (index)
148
- nodes.push(state.schema.nodes.hardbreak.create({ isHTML: index === lines.length - 1 && line === '' }, null, marks));
149
- if (line)
150
- nodes.push(state.schema.text(line, marks));
151
- });
152
- content = Fragment.fromArray(nodes);
153
- }
154
- tr.replace(match.from, match.to, new Slice(content, 0, 0));
158
+ tr.replace(match.from, match.to, replacementSlice(state, match.from, match.to, value));
155
159
  }
156
160
  if (!all) {
157
161
  const match = changed[0];
@@ -169,3 +173,30 @@ export function replaceFormatted(view, search, replacement, preflight, all = fal
169
173
  view.dispatch(closeHistory(view.state.tr).setMeta('addToHistory', false));
170
174
  return changed.length;
171
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.doc);
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/source.d.ts CHANGED
@@ -14,4 +14,3 @@ export declare function sourceSelection(source: string, start: number, end: numb
14
14
  markdown: string;
15
15
  shareable: string;
16
16
  };
17
- export declare function revealSourceCaret(plain: HTMLTextAreaElement): void;
package/dist/source.js CHANGED
@@ -55,63 +55,3 @@ export function sourceSelection(source, start, end) {
55
55
  shareable += source.slice(cursor, to);
56
56
  return { markdown: source.slice(from, to), shareable };
57
57
  }
58
- export function revealSourceCaret(plain) {
59
- if (!plain.clientWidth || !plain.clientHeight)
60
- return;
61
- const document = plain.ownerDocument;
62
- const style = document.defaultView.getComputedStyle(plain);
63
- const mirror = document.createElement('div');
64
- for (const property of [
65
- 'font',
66
- 'font-family',
67
- 'font-size',
68
- 'font-weight',
69
- 'font-style',
70
- 'font-stretch',
71
- 'font-variant',
72
- 'line-height',
73
- 'letter-spacing',
74
- 'word-spacing',
75
- 'tab-size',
76
- 'padding',
77
- 'text-indent',
78
- 'text-transform',
79
- 'direction',
80
- 'word-break',
81
- ])
82
- mirror.style.setProperty(property, style.getPropertyValue(property));
83
- Object.assign(mirror.style, {
84
- position: 'fixed',
85
- visibility: 'hidden',
86
- left: '-10000px',
87
- top: '0',
88
- width: `${plain.clientWidth}px`,
89
- boxSizing: 'border-box',
90
- whiteSpace: plain.wrap === 'off' ? 'pre' : 'pre-wrap',
91
- overflowWrap: plain.wrap === 'off' ? 'normal' : 'break-word',
92
- });
93
- mirror.setAttribute('aria-hidden', 'true');
94
- const caret = document.createElement('span');
95
- caret.setAttribute('data-inkkit-source-caret', '');
96
- caret.textContent = plain.value.slice(plain.selectionStart) || '\u200b';
97
- mirror.append(document.createTextNode(plain.value.slice(0, plain.selectionStart)), caret);
98
- document.body.append(mirror);
99
- try {
100
- // Textareas expose selection offsets but no caret geometry; matching their layout also accounts for wrapped lines.
101
- const rect = caret.getClientRects()[0] ?? caret.getBoundingClientRect();
102
- const top = rect.top - mirror.getBoundingClientRect().top;
103
- const lineHeight = Math.max(rect.height, Number.parseFloat(style.lineHeight) || rect.height);
104
- const insetTop = Number.parseFloat(style.paddingTop) || 0;
105
- const insetBottom = Number.parseFloat(style.paddingBottom) || 0;
106
- if (plain.selectionStart === 0)
107
- plain.scrollTop = 0;
108
- else if (top < plain.scrollTop + insetTop)
109
- plain.scrollTop = Math.max(0, top - insetTop);
110
- else if (top + lineHeight >
111
- plain.scrollTop + plain.clientHeight - insetBottom)
112
- plain.scrollTop = Math.max(0, top + lineHeight - plain.clientHeight + insetBottom);
113
- }
114
- finally {
115
- mirror.remove();
116
- }
117
- }
package/dist/style.css CHANGED
@@ -235,6 +235,45 @@
235
235
  background: var(--_inkkit-accent);
236
236
  }
237
237
 
238
+ .inkkit-root .ProseMirror .inkkit-file {
239
+ vertical-align: middle;
240
+ border: 1px solid var(--_inkkit-rule);
241
+ border-radius: 4px;
242
+ padding: 4px;
243
+ white-space: normal;
244
+ }
245
+
246
+ .inkkit-root .ProseMirror .inkkit-file audio,
247
+ .inkkit-root .ProseMirror .inkkit-file video,
248
+ .inkkit-root .ProseMirror .inkkit-file iframe {
249
+ display: block;
250
+ max-width: 100%;
251
+ }
252
+
253
+ .inkkit-root .ProseMirror .inkkit-file video {
254
+ max-height: 480px;
255
+ }
256
+
257
+ .inkkit-root .ProseMirror .inkkit-file iframe {
258
+ width: min(600px, 100%);
259
+ height: 360px;
260
+ border: 0;
261
+ }
262
+
263
+ .inkkit-root .ProseMirror .inkkit-file-label {
264
+ overflow-wrap: anywhere;
265
+ }
266
+
267
+ .inkkit-root .ProseMirror .inkkit-file-control {
268
+ margin-inline-start: 0.5em;
269
+ font: inherit;
270
+ color: var(--_inkkit-text);
271
+ background: var(--_inkkit-code-bg);
272
+ border: 1px solid var(--_inkkit-rule);
273
+ border-radius: 3px;
274
+ cursor: pointer;
275
+ }
276
+
238
277
  .inkkit-root .ProseMirror {
239
278
  /* The viewport, not the wrapper Milkdown adds, so a click below the text still places the caret. */
240
279
  min-height: var(--inkkit-min-height, 100%);
@@ -0,0 +1,26 @@
1
+ import type { Node as ProseNode } from '@milkdown/kit/prose/model';
2
+ import type { EditorView } from '@milkdown/kit/prose/view';
3
+ import { type TextRect } from './types.js';
4
+ export interface TextSpan {
5
+ from: number;
6
+ to: number;
7
+ start: number;
8
+ end: number;
9
+ kind: 'text' | 'break' | 'embed' | 'separator';
10
+ }
11
+ export interface TextProjection {
12
+ text: string;
13
+ spans: TextSpan[];
14
+ }
15
+ export declare function readableProjection(doc: ProseNode): TextProjection;
16
+ export declare function projectionPosition(projection: TextProjection, offset: number, side: -1 | 1): number;
17
+ export declare function projectionOffset(projection: TextProjection, position: number): number;
18
+ export declare function validateOffsets(text: string, from: number, to: number): void;
19
+ export declare function textRect(rect: Pick<TextRect, 'left' | 'top' | 'right' | 'bottom'>): TextRect;
20
+ export declare function formattedRects(view: EditorView, projection: TextProjection, from: number, to: number): TextRect[];
21
+ export declare function literalRects(plain: HTMLTextAreaElement, from: number, to: number): TextRect[];
22
+ export declare function intersectsViewport(rect: Pick<TextRect, 'top' | 'right' | 'bottom' | 'left'>, viewport: TextRect): boolean;
23
+ export declare function literalVisibleRanges(plain: HTMLTextAreaElement, viewport: TextRect): {
24
+ from: number;
25
+ to: number;
26
+ }[];
@@ -0,0 +1,233 @@
1
+ import { InkKitError } from './types.js';
2
+ import { fileReference } from './linked-syntax.js';
3
+ export function readableProjection(doc) {
4
+ const result = { text: '', spans: [] };
5
+ let blocks = 0;
6
+ const append = (text, start, end, kind) => {
7
+ const from = result.text.length;
8
+ result.text += text;
9
+ result.spans.push({ from, to: result.text.length, start, end, kind });
10
+ };
11
+ const block = (start) => {
12
+ if (blocks++)
13
+ append('\n', result.spans.at(-1)?.end ?? start, start, 'separator');
14
+ };
15
+ doc.descendants((node, position) => {
16
+ const name = node.type.name;
17
+ if (name === 'comment_inline' ||
18
+ name === 'comment_block' ||
19
+ name === 'reference_definition')
20
+ return false;
21
+ if (name === 'inkkit_callout') {
22
+ block(position);
23
+ append(node.attrs.title ||
24
+ String(node.attrs.kind).replace(/^./, (value) => value.toUpperCase()), position, position + 1, 'embed');
25
+ return true;
26
+ }
27
+ if (node.isTextblock) {
28
+ block(position + 1);
29
+ if (!node.content.size)
30
+ append('', position + 1, position + 1, 'text');
31
+ return true;
32
+ }
33
+ if (node.isText) {
34
+ append(node.text ?? '', position, position + node.nodeSize, 'text');
35
+ return false;
36
+ }
37
+ if (name === 'hardbreak' || name === 'hard_break') {
38
+ append('\n', position, position + node.nodeSize, 'break');
39
+ return false;
40
+ }
41
+ if (name === 'image' ||
42
+ name === 'footnote_reference' ||
43
+ name === 'inkkit_wiki_link') {
44
+ append(name === 'image'
45
+ ? fileReference(node).label || 'Image'
46
+ : name === 'inkkit_wiki_link'
47
+ ? String(node.attrs.label || node.attrs.target || 'Link')
48
+ : `[${node.attrs.label}]`, position, position + node.nodeSize, 'embed');
49
+ return false;
50
+ }
51
+ return true;
52
+ });
53
+ return result;
54
+ }
55
+ export function projectionPosition(projection, offset, side) {
56
+ const spans = projection.spans;
57
+ const span = spans.find((span) => (offset > span.from && offset < span.to) ||
58
+ (side > 0 ? offset === span.from : offset === span.to)) ?? (side > 0 ? spans.at(-1) : spans[0]);
59
+ if (!span)
60
+ return 0;
61
+ if (span.kind === 'text')
62
+ return (span.start +
63
+ Math.max(0, Math.min(offset - span.from, span.to - span.from)));
64
+ return offset <= span.from ? span.start : span.end;
65
+ }
66
+ export function projectionOffset(projection, position) {
67
+ for (const span of projection.spans) {
68
+ if (position < span.start)
69
+ return span.from;
70
+ if (position <= span.end)
71
+ return span.kind === 'text'
72
+ ? span.from + Math.max(0, position - span.start)
73
+ : position === span.start
74
+ ? span.from
75
+ : span.to;
76
+ }
77
+ return projection.text.length;
78
+ }
79
+ export function validateOffsets(text, from, to) {
80
+ const split = (offset) => offset > 0 &&
81
+ offset < text.length &&
82
+ /[\uD800-\uDBFF]/.test(text[offset - 1]) &&
83
+ /[\uDC00-\uDFFF]/.test(text[offset]);
84
+ if (!Number.isInteger(from) ||
85
+ !Number.isInteger(to) ||
86
+ from < 0 ||
87
+ to < from ||
88
+ to > text.length ||
89
+ split(from) ||
90
+ split(to))
91
+ throw new InkKitError('invalid-range', 'Range must use valid UTF-16 boundaries in the text snapshot');
92
+ }
93
+ export function textRect(rect) {
94
+ return {
95
+ left: rect.left,
96
+ top: rect.top,
97
+ right: rect.right,
98
+ bottom: rect.bottom,
99
+ width: Math.max(0, rect.right - rect.left),
100
+ height: Math.max(0, rect.bottom - rect.top),
101
+ };
102
+ }
103
+ export function formattedRects(view, projection, from, to) {
104
+ if (from === to) {
105
+ const position = projectionPosition(projection, from, 1);
106
+ const dom = view.domAtPos(position);
107
+ const element = dom.node.nodeType === 1 ? dom.node : dom.node.parentElement;
108
+ if (!element?.getClientRects().length)
109
+ return [];
110
+ return [textRect(view.coordsAtPos(position))];
111
+ }
112
+ const rects = [];
113
+ for (const span of projection.spans) {
114
+ if (span.to <= from || span.from >= to || span.kind === 'separator')
115
+ continue;
116
+ if (span.kind === 'embed' || span.kind === 'break') {
117
+ const node = view.nodeDOM(span.start);
118
+ if (node instanceof Element) {
119
+ const label = node.matches('.inkkit-callout')
120
+ ? (node.querySelector(':scope > .inkkit-callout-header > .inkkit-callout-title') ?? node)
121
+ : node;
122
+ rects.push(...Array.from(label.getClientRects(), textRect));
123
+ }
124
+ continue;
125
+ }
126
+ const start = view.domAtPos(span.start + Math.max(0, from - span.from), 1);
127
+ const end = view.domAtPos(span.start + Math.min(span.to - span.from, to - span.from), -1);
128
+ const range = view.dom.ownerDocument.createRange();
129
+ range.setStart(start.node, start.offset);
130
+ range.setEnd(end.node, end.offset);
131
+ rects.push(...Array.from(range.getClientRects(), textRect));
132
+ }
133
+ return rects.filter((rect) => rect.height > 0 && rect.width >= 0);
134
+ }
135
+ function withLiteralLayout(plain, measure) {
136
+ if (!plain.clientWidth || !plain.clientHeight)
137
+ return undefined;
138
+ const document = plain.ownerDocument;
139
+ const style = document.defaultView.getComputedStyle(plain);
140
+ const mirror = document.createElement('div');
141
+ for (const property of [
142
+ 'font',
143
+ 'font-family',
144
+ 'font-size',
145
+ 'font-weight',
146
+ 'font-style',
147
+ 'font-stretch',
148
+ 'font-variant',
149
+ 'line-height',
150
+ 'letter-spacing',
151
+ 'word-spacing',
152
+ 'tab-size',
153
+ 'padding',
154
+ 'text-indent',
155
+ 'text-transform',
156
+ 'direction',
157
+ 'word-break',
158
+ ])
159
+ mirror.style.setProperty(property, style.getPropertyValue(property));
160
+ const origin = plain.getBoundingClientRect();
161
+ Object.assign(mirror.style, {
162
+ position: 'fixed',
163
+ visibility: 'hidden',
164
+ pointerEvents: 'none',
165
+ left: `${origin.left + plain.clientLeft - plain.scrollLeft}px`,
166
+ top: `${origin.top + plain.clientTop - plain.scrollTop}px`,
167
+ width: `${plain.clientWidth}px`,
168
+ boxSizing: 'border-box',
169
+ whiteSpace: plain.wrap === 'off' ? 'pre' : 'pre-wrap',
170
+ overflowWrap: plain.wrap === 'off' ? 'normal' : 'break-word',
171
+ });
172
+ mirror.setAttribute('aria-hidden', 'true');
173
+ const text = document.createTextNode(plain.value + '\u200b');
174
+ mirror.append(text);
175
+ document.body.append(mirror);
176
+ try {
177
+ return measure(text);
178
+ }
179
+ finally {
180
+ mirror.remove();
181
+ }
182
+ }
183
+ export function literalRects(plain, from, to) {
184
+ return (withLiteralLayout(plain, (text) => {
185
+ const range = plain.ownerDocument.createRange();
186
+ range.setStart(text, from);
187
+ range.setEnd(text, from === to ? Math.min(to + 1, text.length) : to);
188
+ return Array.from(range.getClientRects(), (rect) => textRect({
189
+ left: rect.left,
190
+ right: from === to ? rect.left : rect.right,
191
+ top: rect.top,
192
+ bottom: rect.bottom,
193
+ }));
194
+ }) ?? []);
195
+ }
196
+ export function intersectsViewport(rect, viewport) {
197
+ return (viewport.width > 0 &&
198
+ viewport.height > 0 &&
199
+ rect.bottom > viewport.top &&
200
+ rect.top < viewport.bottom &&
201
+ rect.right >= viewport.left &&
202
+ rect.left < viewport.right);
203
+ }
204
+ export function literalVisibleRanges(plain, viewport) {
205
+ return (withLiteralLayout(plain, (text) => {
206
+ const range = plain.ownerDocument.createRange();
207
+ const ranges = [];
208
+ const visible = (from, to) => {
209
+ range.setStart(text, from);
210
+ range.setEnd(text, to);
211
+ return Array.from(range.getClientRects()).some((rect) => intersectsViewport(rect, viewport));
212
+ };
213
+ for (let start = 0; start < plain.value.length;) {
214
+ const newline = plain.value.indexOf('\n', start);
215
+ const end = newline < 0 ? plain.value.length : newline + 1;
216
+ if (visible(start, end)) {
217
+ for (let from = start; from < end;) {
218
+ const to = from + (plain.value.codePointAt(from) > 0xffff ? 2 : 1);
219
+ if (visible(from, to)) {
220
+ const previous = ranges.at(-1);
221
+ if (previous?.to === from)
222
+ previous.to = to;
223
+ else
224
+ ranges.push({ from, to });
225
+ }
226
+ from = to;
227
+ }
228
+ }
229
+ start = end;
230
+ }
231
+ return ranges;
232
+ }) ?? []);
233
+ }
package/dist/types.d.ts CHANGED
@@ -14,7 +14,7 @@ export interface DocumentSnapshot extends DocumentInput {
14
14
  revision: number;
15
15
  dirty: boolean;
16
16
  }
17
- export type EditorErrorCode = 'not-ready' | 'stale-document' | 'composition' | 'read-only' | 'operation-pending' | 'destroyed' | 'preservation' | 'image-unavailable' | 'diagram-unavailable';
17
+ export type EditorErrorCode = 'not-ready' | 'stale-document' | 'composition' | 'read-only' | 'operation-pending' | 'destroyed' | 'preservation' | 'image-unavailable' | 'diagram-unavailable' | 'invalid-range';
18
18
  export declare class InkKitError extends Error {
19
19
  readonly code: EditorErrorCode;
20
20
  constructor(code: EditorErrorCode, message: string);
@@ -39,6 +39,49 @@ export interface ImageAdapter {
39
39
  }>;
40
40
  exportImage(reference: string, context: DocumentContext): Promise<PortableImage>;
41
41
  }
42
+ export interface WikiLinkReference {
43
+ target: string;
44
+ fragment?: string;
45
+ label: string;
46
+ }
47
+ export interface WikiLinkAdapter {
48
+ resolve?(reference: WikiLinkReference, context: DocumentContext): {
49
+ missing?: boolean;
50
+ } | undefined;
51
+ open(reference: WikiLinkReference, context: DocumentContext): void;
52
+ }
53
+ export interface FileReference {
54
+ reference: string;
55
+ kind: 'path' | 'wiki';
56
+ fragment?: string;
57
+ label?: string;
58
+ width?: number;
59
+ }
60
+ export interface FileContext extends DocumentContext {
61
+ signal: AbortSignal;
62
+ }
63
+ export type FilePresentation = {
64
+ kind: 'image' | 'audio' | 'video' | 'pdf';
65
+ url: string;
66
+ label?: string;
67
+ mimeType?: string;
68
+ } | {
69
+ kind: 'file' | 'missing';
70
+ label?: string;
71
+ } | {
72
+ kind: 'error';
73
+ label?: string;
74
+ message: string;
75
+ };
76
+ export interface FileAdapter {
77
+ resolve(reference: FileReference, context: FileContext): Promise<FilePresentation>;
78
+ exportImage?(reference: FileReference, context: FileContext): Promise<PortableImage>;
79
+ open?(reference: FileReference, context: DocumentContext): void;
80
+ contextMenu?(reference: FileReference, point: {
81
+ clientX: number;
82
+ clientY: number;
83
+ }, context: DocumentContext): void;
84
+ }
42
85
  export interface ClipboardInput {
43
86
  text: string;
44
87
  markdown?: string;
@@ -65,7 +108,7 @@ export interface ClipboardDiagram {
65
108
  error?: string;
66
109
  }
67
110
  export interface PrintableWarning {
68
- code: 'diagram-unavailable';
111
+ code: 'diagram-unavailable' | 'attachment-fallback' | 'attachment-unavailable';
69
112
  message: string;
70
113
  }
71
114
  export interface PrintableDocument {
@@ -78,3 +121,42 @@ export interface PrintableDocument {
78
121
  assets: readonly PortableImage[];
79
122
  warnings: readonly PrintableWarning[];
80
123
  }
124
+ export interface TextRange {
125
+ snapshotId: string;
126
+ from: number;
127
+ to: number;
128
+ }
129
+ export interface ReadableTextSnapshot {
130
+ snapshotId: string;
131
+ documentId: string;
132
+ generation: number;
133
+ revision: number;
134
+ format: DocumentFormat;
135
+ mode: 'source' | 'formatted';
136
+ text: string;
137
+ selection: TextRange;
138
+ }
139
+ export interface TextRect {
140
+ left: number;
141
+ top: number;
142
+ right: number;
143
+ bottom: number;
144
+ width: number;
145
+ height: number;
146
+ }
147
+ export interface ViewportInsets {
148
+ top: number;
149
+ right: number;
150
+ bottom: number;
151
+ left: number;
152
+ }
153
+ export interface ViewportOptions {
154
+ scrollContainer?: HTMLElement;
155
+ insets?: Partial<ViewportInsets>;
156
+ }
157
+ export interface ViewportSnapshot {
158
+ rect: TextRect;
159
+ insets: ViewportInsets;
160
+ scrollTop: number;
161
+ scrollLeft: number;
162
+ }
@@ -0,0 +1,21 @@
1
+ import type { Node as ProseNode } from '@milkdown/kit/prose/model';
2
+ import type { EditorView } from '@milkdown/kit/prose/view';
3
+ import type { DocumentContext, WikiLinkAdapter } from './types.js';
4
+ import type { EditorLabels } from './labels.js';
5
+ interface WikiRuntime {
6
+ capture(): {
7
+ context: DocumentContext;
8
+ isCurrent(): boolean;
9
+ };
10
+ active(): boolean;
11
+ labels: Readonly<EditorLabels>;
12
+ error?(error: Error): void;
13
+ }
14
+ export declare function wikiLinkView(adapter: WikiLinkAdapter, runtime: WikiRuntime): import("@milkdown/kit/utils").$View<import("@milkdown/kit/utils").$Node, (node: ProseNode, view: EditorView) => {
15
+ dom: HTMLSpanElement;
16
+ update(next: ProseNode): boolean;
17
+ stopEvent(event: Event): boolean;
18
+ ignoreMutation: () => true;
19
+ destroy(): void;
20
+ }>;
21
+ export {};