@aicayzer/inkkit 0.0.9 → 0.0.11

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/editor.js CHANGED
@@ -21,10 +21,11 @@ import { sourceAttribute, cleanSourceDoc, editedPlainSource, sourceSelection, ra
21
21
  import { normaliseLabel, referenceDefinitions, footnoteDefinitions, } from './references.js';
22
22
  import { selectionMarkdown, selectionContent, referenceMetadata, withReferenceMetadata, } from './reference-clipboard.js';
23
23
  import { imageView } from './images.js';
24
+ import { wikiLinkView } from './wiki-view.js';
25
+ import { withFileSignal } from './files.js';
24
26
  import { tablePlugins, tableCommand, tableCommands, tableAvailability, tableContext, configureTableMovement, } from './tables.js';
25
27
  import { InkKitError, } from './types.js';
26
28
  import { readableProjection, projectionPosition, projectionOffset, validateOffsets, formattedRects, literalRects, literalVisibleRanges, intersectsViewport, textRect, } from './text-ranges.js';
27
- import { highlightPlugin } from './highlight.js';
28
29
  import { highlightKeymap, toggleHighlightCommand } from './inline-highlight.js';
29
30
  import { commentSelectionContent, setCommentVisibility } from './comments.js';
30
31
  import { PasteController } from './paste.js';
@@ -251,12 +252,14 @@ export class InkKitEditor {
251
252
  revision = 0;
252
253
  documentEpoch = 0;
253
254
  operationSequence = 0;
255
+ exportControllers = new Set();
254
256
  plainComposing = false;
255
257
  plainSearch = '';
256
258
  literalMatch;
257
259
  beforePlainInput;
258
260
  mode = 'formatted';
259
261
  sourcePreservations = new WeakMap();
262
+ sourceTexts = new WeakMap();
260
263
  outlineEpoch = 0;
261
264
  ready = false;
262
265
  destroyed = false;
@@ -294,6 +297,8 @@ export class InkKitEditor {
294
297
  if (this.loading || view.state.doc.eq(previous.doc))
295
298
  return;
296
299
  this.revision += 1;
300
+ this.cancelExports();
301
+ this.mediaPolicy();
297
302
  this.literalMatch = undefined;
298
303
  let markdown;
299
304
  try {
@@ -335,6 +340,36 @@ export class InkKitEditor {
335
340
  operationId: `${this.documentEpoch}:${this.generation}:${++this.operationSequence}`,
336
341
  };
337
342
  }
343
+ cancelExports() {
344
+ for (const controller of this.exportControllers)
345
+ controller.abort();
346
+ this.exportControllers.clear();
347
+ }
348
+ async exportContent(snapshot, operation) {
349
+ const epoch = this.documentEpoch;
350
+ const mode = this.editingMode;
351
+ const controller = new AbortController();
352
+ this.exportControllers.add(controller);
353
+ try {
354
+ return await withFileSignal(operation(controller.signal), controller.signal);
355
+ }
356
+ finally {
357
+ this.exportControllers.delete(controller);
358
+ this.assertCurrent(snapshot.generation);
359
+ if (controller.signal.aborted ||
360
+ epoch !== this.documentEpoch ||
361
+ snapshot.documentId !== this.documentId ||
362
+ snapshot.revision !== this.revision ||
363
+ mode !== this.editingMode)
364
+ throw new InkKitError('stale-document', 'Document changed while preparing output');
365
+ }
366
+ }
367
+ mediaPolicy() {
368
+ if (this.editor && this.root)
369
+ this.editor.ctx
370
+ .get(editorViewCtx)
371
+ .dom.dispatchEvent(new Event('inkkit-media-policy'));
372
+ }
338
373
  assertAlive() {
339
374
  if (this.destroyed)
340
375
  throw new InkKitError('destroyed', 'The editor has been destroyed');
@@ -383,6 +418,7 @@ export class InkKitEditor {
383
418
  .get(editorViewCtx)
384
419
  .dom.dispatchEvent(new Event('inkkit-cancel-resize'));
385
420
  this.applyInputPolicy();
421
+ this.mediaPolicy();
386
422
  }
387
423
  finally {
388
424
  this.reportingSuppressed = suppressed;
@@ -566,6 +602,9 @@ export class InkKitEditor {
566
602
  return this.literalSurface ? 'source' : 'formatted';
567
603
  }
568
604
  currentText(doc = this.editor.ctx.get(editorViewCtx).state.doc) {
605
+ const cached = this.sourceTexts.get(doc);
606
+ if (cached !== undefined)
607
+ return cached;
569
608
  const provenance = doc.attrs[sourceAttribute];
570
609
  if (this.formatType === 'txt')
571
610
  return provenance?.text ?? this.originalSource;
@@ -577,7 +616,9 @@ export class InkKitEditor {
577
616
  this.sourcePreservations.set(provenance, preservation);
578
617
  }
579
618
  }
580
- return preservation.serialize(cleanSourceDoc(doc));
619
+ const text = preservation.serialize(cleanSourceDoc(doc));
620
+ this.sourceTexts.set(doc, text);
621
+ return text;
581
622
  }
582
623
  setEditingMode(mode, expectedGeneration) {
583
624
  this.assertCurrent(expectedGeneration);
@@ -593,6 +634,7 @@ export class InkKitEditor {
593
634
  const top = container.scrollTop, left = container.scrollLeft;
594
635
  const text = this.snapshot().text;
595
636
  this.mode = mode;
637
+ this.cancelExports();
596
638
  this.outlineEpoch += 1;
597
639
  this.plainSearch = '';
598
640
  this.literalMatch = undefined;
@@ -631,6 +673,7 @@ export class InkKitEditor {
631
673
  : (this.options.labels?.sourceEditor ?? defaultLabels.sourceEditor));
632
674
  this.editor.ctx.get(editorViewCtx).dom.parentElement.hidden =
633
675
  this.literalSurface;
676
+ this.mediaPolicy();
634
677
  }
635
678
  replaceSource(text, expectedGeneration) {
636
679
  this.assertMutation(expectedGeneration);
@@ -735,26 +778,17 @@ export class InkKitEditor {
735
778
  }
736
779
  async printableSnapshot(expectedGeneration) {
737
780
  const snapshot = this.snapshot(expectedGeneration);
738
- const epoch = this.documentEpoch;
739
781
  const state = this.editor.ctx.get(editorViewCtx).state;
740
- let output;
741
- try {
782
+ const output = await this.exportContent(snapshot, async (signal) => {
742
783
  if (snapshot.format === 'md' &&
743
784
  !this.options.images &&
785
+ !this.options.files &&
744
786
  hasAuthoredImagesInLiterals(state.doc.content, (source) => this.editor.ctx.get(remarkCtx).parse(source)))
745
787
  throw new InkKitError('image-unavailable', 'No image adapter is configured for the authored images.');
746
- output =
747
- snapshot.format === 'txt'
748
- ? printableText(snapshot.text)
749
- : await printableMarkdown(state.doc.content, state.schema, this.options.images, this.context());
750
- }
751
- finally {
752
- this.assertCurrent(snapshot.generation);
753
- if (snapshot.documentId !== this.documentId ||
754
- epoch !== this.documentEpoch ||
755
- snapshot.revision !== this.revision)
756
- throw new InkKitError('stale-document', 'Document changed while preparing printable content');
757
- }
788
+ return snapshot.format === 'txt'
789
+ ? printableText(snapshot.text)
790
+ : printableMarkdown(state.doc.content, state.schema, this.options.images, this.context(), this.options.files, signal);
791
+ });
758
792
  return Object.freeze({
759
793
  documentId: snapshot.documentId,
760
794
  generation: snapshot.generation,
@@ -827,7 +861,7 @@ export class InkKitEditor {
827
861
  ? error.message
828
862
  : 'Cannot copy the selected Markdown');
829
863
  }
830
- const result = await portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.options.images, this.context(), completeDiagrams);
864
+ const result = await this.exportContent(snapshot, (signal) => portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.options.images, this.context(), completeDiagrams, this.options.files, signal));
831
865
  const metadata = referenceMetadata(this.editor.ctx, selectedDoc ?? doc, content);
832
866
  if (metadata != null)
833
867
  result.html = withReferenceMetadata(result.html, metadata);
@@ -870,28 +904,41 @@ export class InkKitEditor {
870
904
  }
871
905
  else {
872
906
  const { schema } = view.state;
907
+ const marks = view.state.storedMarks ??
908
+ (view.state.selection.empty
909
+ ? view.state.selection.$from.marks()
910
+ : view.state.selection.$from.marksAcross(view.state.selection.$to)) ??
911
+ [];
873
912
  const children = [];
874
- text
875
- .replace(/\r\n?/g, '\n')
876
- .split('\n')
877
- .forEach((line, index) => {
913
+ const lines = text.replace(/\r\n?/g, '\n').split('\n');
914
+ lines.forEach((line, index) => {
915
+ const finalBreak = index === lines.length - 1 && line === '';
878
916
  if (index)
879
917
  children.push(schema.nodes.hardbreak.create({
880
- isHTML: index ===
881
- text.replace(/\r\n?/g, '\n').split('\n').length - 1 &&
882
- line === '',
883
- }));
918
+ isHTML: finalBreak,
919
+ }, null,
920
+ // A terminal HTML spacer must remain outside emphasis to reopen as a break.
921
+ finalBreak ? [] : marks));
884
922
  if (line)
885
- children.push(schema.text(line));
923
+ children.push(schema.text(line, marks));
886
924
  });
887
925
  if (!children.length) {
888
926
  view.dispatch(view.state.tr.deleteSelection());
889
927
  return;
890
928
  }
891
929
  const paragraph = schema.nodes.paragraph.create(null, children);
892
- view.dispatch(view.state.tr
930
+ const transaction = view.state.tr
893
931
  .replaceSelection(new Slice(Fragment.from(paragraph), 1, 1))
894
- .scrollIntoView());
932
+ .scrollIntoView();
933
+ try {
934
+ this.currentText(transaction.doc);
935
+ }
936
+ catch (error) {
937
+ throw new InkKitError('preservation', error instanceof Error
938
+ ? error.message
939
+ : 'Cannot preserve inserted text');
940
+ }
941
+ view.dispatch(transaction);
895
942
  }
896
943
  }
897
944
  }
@@ -906,6 +953,8 @@ export class InkKitEditor {
906
953
  return;
907
954
  this.destroyed = true;
908
955
  this.ready = false;
956
+ this.cancelExports();
957
+ this.mediaPolicy();
909
958
  this.pasteController.destroy();
910
959
  if (this.clickHandler)
911
960
  this.root.removeEventListener('click', this.clickHandler);
@@ -1052,7 +1101,7 @@ export class InkKitEditor {
1052
1101
  .use(instance.pasteController.plugin)
1053
1102
  .use(visibleClipboard)
1054
1103
  .use(instance.keymapPlugin)
1055
- .use(createDialect(Boolean(options.images)))
1104
+ .use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files)))
1056
1105
  .use(tablePlugins)
1057
1106
  .use(instance.changePlugin)
1058
1107
  .use(history)
@@ -1065,12 +1114,66 @@ export class InkKitEditor {
1065
1114
  .use(dropControlCharacters)
1066
1115
  .use(codeCopyPlugin((text) => events.copy(text)))
1067
1116
  .use(placeholderPlugin)
1068
- .use(highlightPlugin)
1069
- .use(mermaidPreview((error) => events.error?.(error)))
1117
+ .use(options.rendering?.codeHighlighting === false
1118
+ ? []
1119
+ : (await import('./highlight')).highlightPlugin)
1120
+ .use(options.rendering?.diagramPreview === false
1121
+ ? []
1122
+ : mermaidPreview((error) => events.error?.(error)))
1070
1123
  .use(selectionPlugin)
1071
1124
  .use($prose(() => search()))
1072
1125
  .use(instance.policyPlugin)
1073
- .use(options.images ? imageView(options.images) : [])
1126
+ .use(options.wikiLinks
1127
+ ? wikiLinkView(options.wikiLinks, {
1128
+ capture: () => {
1129
+ const epoch = instance.documentEpoch;
1130
+ const context = instance.context();
1131
+ return {
1132
+ context,
1133
+ isCurrent: () => !instance.destroyed &&
1134
+ epoch === instance.documentEpoch &&
1135
+ context.documentId === instance.documentId &&
1136
+ context.generation === instance.generation,
1137
+ };
1138
+ },
1139
+ active: () => instance.ready &&
1140
+ !instance.destroyed &&
1141
+ !instance.literalSurface,
1142
+ labels: { ...defaultLabels, ...options.labels },
1143
+ error: (error) => events.error?.(error),
1144
+ })
1145
+ : [])
1146
+ .use(options.images || options.files
1147
+ ? imageView(options.images, options.files
1148
+ ? {
1149
+ adapter: options.files,
1150
+ capture: () => {
1151
+ const epoch = instance.documentEpoch;
1152
+ const context = instance.context();
1153
+ return {
1154
+ context,
1155
+ isCurrent: () => !instance.destroyed &&
1156
+ epoch === instance.documentEpoch &&
1157
+ context.documentId === instance.documentId &&
1158
+ context.generation === instance.generation,
1159
+ };
1160
+ },
1161
+ active: () => instance.ready &&
1162
+ !instance.destroyed &&
1163
+ !instance.literalSurface,
1164
+ labels: { ...defaultLabels, ...options.labels },
1165
+ error: (error) => events.error?.(error),
1166
+ }
1167
+ : undefined, () => {
1168
+ try {
1169
+ instance.assertMutation();
1170
+ return true;
1171
+ }
1172
+ catch {
1173
+ return false;
1174
+ }
1175
+ })
1176
+ : [])
1074
1177
  .create();
1075
1178
  configureTableMovement(instance.editor.ctx, () => {
1076
1179
  try {
@@ -1275,10 +1378,13 @@ export class InkKitEditor {
1275
1378
  ? this.plain.ownerDocument.activeElement === this.plain
1276
1379
  : this.editor.ctx.get(editorViewCtx).hasFocus();
1277
1380
  this.ready = false;
1381
+ this.cancelExports();
1382
+ this.mediaPolicy();
1278
1383
  this.pasteController.cancelPending();
1279
1384
  this.documentEpoch += 1;
1280
1385
  this.outlineEpoch += 1;
1281
1386
  this.sourcePreservations = new WeakMap();
1387
+ this.sourceTexts = new WeakMap();
1282
1388
  this.mode = 'formatted';
1283
1389
  this.plainComposing = false;
1284
1390
  this.beforePlainInput = undefined;
@@ -1294,6 +1400,7 @@ export class InkKitEditor {
1294
1400
  this.lastMarkdown = input.text;
1295
1401
  this.updateSurface();
1296
1402
  this.ready = true;
1403
+ this.mediaPolicy();
1297
1404
  if (focused) {
1298
1405
  if (this.literalSurface)
1299
1406
  this.plain.focus({ preventScroll: true });
@@ -1794,6 +1901,10 @@ export class InkKitEditor {
1794
1901
  this.replaceLiteralSelection(text, false);
1795
1902
  return true;
1796
1903
  }
1904
+ if (/[\r\n]/.test(text)) {
1905
+ this.pasteAsPlainText(text);
1906
+ return true;
1907
+ }
1797
1908
  const view = this.editor.ctx.get(editorViewCtx);
1798
1909
  if (view.composing)
1799
1910
  return false;
@@ -0,0 +1,40 @@
1
+ import type { DocumentContext, FileAdapter, FileContext, FilePresentation, FileReference } from './types.js';
2
+ import type { EditorLabels } from './labels.js';
3
+ export interface FileViewRuntime {
4
+ adapter: FileAdapter;
5
+ capture(): {
6
+ context: DocumentContext;
7
+ isCurrent(): boolean;
8
+ };
9
+ active(): boolean;
10
+ labels: Readonly<EditorLabels>;
11
+ error?(error: Error): void;
12
+ }
13
+ export declare function withFileSignal<T>(operation: Promise<T>, signal: AbortSignal): Promise<T>;
14
+ export declare function resolveFile(adapter: FileAdapter, reference: FileReference, context: FileContext): Promise<FilePresentation>;
15
+ export type FileResolutionState = {
16
+ status: 'idle';
17
+ } | {
18
+ status: 'loading';
19
+ } | {
20
+ status: 'resolved';
21
+ presentation: FilePresentation;
22
+ } | {
23
+ status: 'failed';
24
+ error: Error;
25
+ };
26
+ export declare class FileResolution {
27
+ private readonly runtime;
28
+ private readonly changed;
29
+ state: FileResolutionState;
30
+ private reference?;
31
+ private key;
32
+ private request?;
33
+ private dead;
34
+ constructor(runtime: FileViewRuntime, changed: () => void);
35
+ update(reference: FileReference): void;
36
+ retry(): void;
37
+ private current;
38
+ cancel(): void;
39
+ destroy(): void;
40
+ }
package/dist/files.js ADDED
@@ -0,0 +1,133 @@
1
+ function abort(signal) {
2
+ if (signal.aborted)
3
+ throw new DOMException('File resolution cancelled', 'AbortError');
4
+ }
5
+ export function withFileSignal(operation, signal) {
6
+ return new Promise((resolve, reject) => {
7
+ const cleanup = () => signal.removeEventListener('abort', cancelled);
8
+ const cancelled = () => {
9
+ cleanup();
10
+ reject(new DOMException('File operation cancelled', 'AbortError'));
11
+ };
12
+ if (signal.aborted)
13
+ cancelled();
14
+ else
15
+ signal.addEventListener('abort', cancelled, { once: true });
16
+ operation.then((result) => {
17
+ cleanup();
18
+ if (signal.aborted)
19
+ cancelled();
20
+ else
21
+ resolve(result);
22
+ }, (error) => {
23
+ cleanup();
24
+ reject(error);
25
+ });
26
+ });
27
+ }
28
+ export async function resolveFile(adapter, reference, context) {
29
+ abort(context.signal);
30
+ const presentation = await withFileSignal(adapter.resolve(Object.freeze({ ...reference }), context), context.signal);
31
+ abort(context.signal);
32
+ if (!presentation ||
33
+ typeof presentation !== 'object' ||
34
+ !['image', 'audio', 'video', 'pdf', 'file', 'missing', 'error'].includes(presentation.kind))
35
+ throw new TypeError('File adapter returned an unsupported presentation');
36
+ if (presentation.label !== undefined &&
37
+ typeof presentation.label !== 'string')
38
+ throw new TypeError('File presentation label must be text');
39
+ if (presentation.kind === 'error' && typeof presentation.message !== 'string')
40
+ throw new TypeError('File presentation error must include a message');
41
+ if ('url' in presentation) {
42
+ if (typeof presentation.url !== 'string' || !presentation.url.trim())
43
+ throw new TypeError('File presentation needs a resource URL');
44
+ const url = new URL(presentation.url, document.baseURI);
45
+ if (['javascript:', 'vbscript:'].includes(url.protocol))
46
+ throw new TypeError('Executable file presentation URLs are not supported');
47
+ const prefix = presentation.kind === 'pdf' ? 'application/pdf' : `${presentation.kind}/`;
48
+ const mime = presentation.mimeType?.toLowerCase().split(';')[0]?.trim();
49
+ if (mime &&
50
+ (presentation.kind === 'pdf' ? mime !== prefix : !mime.startsWith(prefix)))
51
+ throw new TypeError('File presentation MIME type does not match its kind');
52
+ const dataMime = url.pathname.toLowerCase().split(/[;,]/)[0] ?? '';
53
+ if (url.protocol === 'data:' &&
54
+ (presentation.kind === 'pdf'
55
+ ? dataMime !== prefix
56
+ : !dataMime.startsWith(prefix)))
57
+ throw new TypeError('File presentation data URL does not match its kind');
58
+ }
59
+ else if (['image', 'audio', 'video', 'pdf'].includes(presentation.kind)) {
60
+ throw new TypeError('File presentation needs a resource URL');
61
+ }
62
+ return Object.freeze({ ...presentation });
63
+ }
64
+ export class FileResolution {
65
+ runtime;
66
+ changed;
67
+ state = { status: 'idle' };
68
+ reference;
69
+ key = '';
70
+ request;
71
+ dead = false;
72
+ constructor(runtime, changed) {
73
+ this.runtime = runtime;
74
+ this.changed = changed;
75
+ }
76
+ update(reference) {
77
+ const key = JSON.stringify([
78
+ reference.reference,
79
+ reference.kind,
80
+ reference.fragment,
81
+ ]);
82
+ this.reference = Object.freeze({ ...reference });
83
+ if (this.key === key && this.request?.isCurrent())
84
+ return;
85
+ this.key = key;
86
+ this.retry();
87
+ }
88
+ retry() {
89
+ this.cancel();
90
+ if (this.dead || !this.reference || !this.runtime.active())
91
+ return;
92
+ const captured = this.runtime.capture();
93
+ const request = {
94
+ controller: new AbortController(),
95
+ isCurrent: captured.isCurrent,
96
+ };
97
+ this.request = request;
98
+ this.state = { status: 'loading' };
99
+ this.changed();
100
+ void resolveFile(this.runtime.adapter, this.reference, {
101
+ ...captured.context,
102
+ signal: request.controller.signal,
103
+ }).then((presentation) => {
104
+ if (!this.current(request))
105
+ return;
106
+ this.state = { status: 'resolved', presentation };
107
+ this.changed();
108
+ }, (failure) => {
109
+ if (!this.current(request))
110
+ return;
111
+ const error = failure instanceof Error ? failure : new Error(String(failure));
112
+ this.state = { status: 'failed', error };
113
+ this.changed();
114
+ this.runtime.error?.(error);
115
+ });
116
+ }
117
+ current(request) {
118
+ return (!this.dead &&
119
+ this.request === request &&
120
+ !request.controller.signal.aborted &&
121
+ this.runtime.active() &&
122
+ request.isCurrent());
123
+ }
124
+ cancel() {
125
+ this.request?.controller.abort();
126
+ this.request = undefined;
127
+ this.state = { status: 'idle' };
128
+ }
129
+ destroy() {
130
+ this.dead = true;
131
+ this.cancel();
132
+ }
133
+ }
package/dist/images.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Node as ProseNode } from '@milkdown/kit/prose/model';
2
2
  import type { EditorView, NodeView } from '@milkdown/kit/prose/view';
3
3
  import type { ImageAdapter } from './types.js';
4
+ import { type FileViewRuntime } from './files.js';
4
5
  /** A width rides in the alt text, as `![a picture|400](images/….png)`. Other Markdown readers
5
6
  * show the picture and keep the number without requiring a private extension. */
6
7
  export declare function splitAlt(alt: string): {
@@ -8,26 +9,41 @@ export declare function splitAlt(alt: string): {
8
9
  width: number | null;
9
10
  };
10
11
  export declare function joinAlt(alt: string, width: number | null): string;
11
- /** Draws the image and the handle that sizes it. The width is kept in the alt text, so the schema is the
12
- * one commonmark gives us; a picture is never wider than its editor, whatever number the alt text holds. */
13
12
  declare class ImageView implements NodeView {
14
13
  private node;
15
14
  private readonly view;
16
15
  private readonly getPos;
17
16
  private readonly adapter;
17
+ private readonly runtime?;
18
+ private readonly canMutate;
18
19
  dom: HTMLElement;
19
20
  private image?;
21
+ private media?;
22
+ private pdf?;
20
23
  private width;
21
24
  private stopResize?;
22
- constructor(node: ProseNode, view: EditorView, getPos: () => number | undefined, adapter: ImageAdapter | undefined);
25
+ private resolution?;
26
+ private previewFailed;
27
+ constructor(node: ProseNode, view: EditorView, getPos: () => number | undefined, adapter: ImageAdapter | undefined, runtime?: FileViewRuntime | undefined, canMutate?: () => boolean);
28
+ private reference;
29
+ private active;
23
30
  update(node: ProseNode): boolean;
24
31
  stopEvent(event: Event): boolean;
25
32
  ignoreMutation(): boolean;
33
+ private mediaPolicy;
26
34
  private cancelResize;
35
+ private releaseMedia;
27
36
  destroy(): void;
37
+ private button;
38
+ private activate;
39
+ private report;
40
+ private card;
41
+ private failPreview;
28
42
  private render;
43
+ private renderImage;
29
44
  private startResize;
30
45
  private commit;
46
+ private canResize;
31
47
  }
32
- export declare function imageView(adapter?: ImageAdapter): import("@milkdown/kit/utils").$View<import("@milkdown/kit/utils").$Node, (node: ProseNode, view: EditorView, getPos: () => number | undefined) => ImageView>;
48
+ export declare function imageView(adapter?: ImageAdapter, runtime?: FileViewRuntime, canMutate?: () => boolean): import("@milkdown/kit/utils").$View<import("@milkdown/kit/utils").$Node, (node: ProseNode, view: EditorView, getPos: () => number | undefined) => ImageView>;
33
49
  export {};