@aicayzer/inkkit 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { a as Decoration, c as PluginKey, d as __toESM, i as $prose, o as DecorationSet, s as Plugin, u as __commonJSMin } from "./core-DtLNFuDg.js";
1
+ import { a as Decoration, c as PluginKey, d as __toESM, i as $prose, o as DecorationSet, s as Plugin, u as __commonJSMin } from "./core-Dl4jPn_d.js";
2
2
  //#region node_modules/.pnpm/highlight.js@11.11.2/node_modules/highlight.js/es/languages/arduino.js
3
3
  /** @type LanguageFn */
4
4
  function cPlusPlus(hljs) {
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { InkKitEditor } from './editor.js';
2
2
  export type { EditorEvents, EditorOptions, TextInputPreferences, CommandState, EditingMode, CaretState, Mark, Block, FormatCommand, FormatOptions, KeyInput, ImageInsertion, ShortcutName, Keymap, } from './editor.js';
3
3
  export { InkKitError } from './types.js';
4
- export type { DocumentFormat, FormatPromise, OfferedFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, ImageImportContext, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
4
+ export type { DocumentFormat, TextDocumentFormat, TextDocumentInput, RichTextDocumentInput, TextDocumentSnapshot, RichTextDocumentSnapshot, RichTextDocument, RichTextBlock, RichTextListItem, RichTextTableCell, RichTextInline, RichTextMark, FormatLoss, FormatLossCode, ConvertedDocument, FormatPromise, OfferedFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, ImageImportContext, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
5
5
  export type { SlashMenuOptions, SlashCommandName, SlashCommand } from './types.js';
package/dist/core.js CHANGED
@@ -1,2 +1,2 @@
1
- import { r as InkKitError, t as InkKitEditor } from "./chunks/core-DtLNFuDg.js";
1
+ import { r as InkKitError, t as InkKitEditor } from "./chunks/core-Dl4jPn_d.js";
2
2
  export { InkKitEditor, InkKitError };
package/dist/editor.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { SlashMenuOptions } from './types.js';
2
- import { InkKitError, type ClientPoint, type DocumentFormat, type DocumentInput, type DocumentSnapshot, type ImageAdapter, type FileAdapter, type WikiLinkAdapter, type ClipboardInput, type ClipboardOutput, type ClipboardScope, type DocumentVersion, type PrintableDocument, type TextRange, type ReadableTextSnapshot, type TextRect, type ViewportOptions, type ViewportSnapshot, type EditorLabels, type Heading, type TableCommand, type TableOptions, type BlockMoveDirection, type OfferedFormat } from './types.js';
2
+ import { InkKitError, type ClientPoint, type DocumentFormat, type DocumentInput, type DocumentSnapshot, type ConvertedDocument, type TextDocumentFormat, type ImageAdapter, type FileAdapter, type WikiLinkAdapter, type ClipboardInput, type ClipboardOutput, type ClipboardScope, type DocumentVersion, type PrintableDocument, type TextRange, type ReadableTextSnapshot, type TextRect, type ViewportOptions, type ViewportSnapshot, type EditorLabels, type Heading, type TableCommand, type TableOptions, type BlockMoveDirection, type OfferedFormat } from './types.js';
3
3
  /** An inline format that `CaretState` can report. */
4
4
  export type Mark = 'bold' | 'italic' | 'strikethrough' | 'highlight' | 'underline' | 'superscript' | 'subscript' | 'code' | 'link';
5
5
  /** The kind of block that holds the start of the selection. Any other block reports `paragraph`. */
@@ -26,8 +26,10 @@ export interface CaretState {
26
26
  block: Block;
27
27
  /** One quote holds the whole selection; the block is what sits inside it. */
28
28
  quoted: boolean;
29
+ /** In an RTF document, the alignment of the paragraph that holds the start of the selection. */
30
+ align?: 'left' | 'center' | 'right' | 'justify';
29
31
  }
30
- declare const formatCommands: readonly ['heading1', 'heading2', 'heading3', 'heading4', 'heading5', 'heading6', 'paragraph', 'bold', 'italic', 'strikethrough', 'highlight', 'underline', 'superscript', 'subscript', 'code', 'codeBlock', 'quote', 'bulletList', 'orderedList', 'taskList', 'toggleTask', 'link'];
32
+ declare const formatCommands: readonly ['heading1', 'heading2', 'heading3', 'heading4', 'heading5', 'heading6', 'paragraph', 'bold', 'italic', 'strikethrough', 'highlight', 'underline', 'superscript', 'subscript', 'code', 'codeBlock', 'quote', 'bulletList', 'orderedList', 'taskList', 'toggleTask', 'alignLeft', 'alignCenter', 'alignRight', 'alignJustify', 'link'];
31
33
  /** A command for `format`. */
32
34
  export type FormatCommand = (typeof formatCommands)[number];
33
35
  /** `destination` goes only with `link`, and `language` only with `codeBlock`. */
@@ -66,10 +68,10 @@ export interface TextInputPreferences {
66
68
  smartPunctuation?: boolean;
67
69
  }
68
70
  /** Mount options. Adapters, `formats`, `labels`, `linkSchemes` and `rendering` are fixed at mount;
69
- * the rest can change. */
70
- export interface EditorOptions {
71
+ * the rest can change. `F` is the formats offered. */
72
+ export interface EditorOptions<F extends DocumentFormat = TextDocumentFormat> {
71
73
  /** The formats the host offers, listed by `formats`. Defaults to `['md', 'txt']`. Fixed at mount. */
72
- formats?: readonly DocumentFormat[];
74
+ formats?: readonly F[];
73
75
  /** Shows, imports and exports images. Without it and `files`, image Markdown stays literal. */
74
76
  images?: ImageAdapter;
75
77
  /** Opt-in block suggestions on an empty line. Fixed at mount. */
@@ -130,10 +132,10 @@ export interface CommandState extends DocumentVersion {
130
132
  moveBlockDown: boolean;
131
133
  };
132
134
  }
133
- /** The host's handlers, passed to `mount`. Only `changed` is required. */
134
- export interface EditorEvents {
135
- /** The document's text changed. Not sent for a load, a reload or a refused edit. */
136
- changed(snapshot: DocumentSnapshot): void;
135
+ /** The host's handlers, passed to `mount`. Only `changed` is required. `F` is the formats offered. */
136
+ export interface EditorEvents<F extends DocumentFormat = TextDocumentFormat> {
137
+ /** The document changed. Not sent for a load, a reload or a refused edit. */
138
+ changed(snapshot: DocumentSnapshot<F>): void;
137
139
  /** Availability or the caret changed, and once after each load. */
138
140
  commandStateChanged?(state: CommandState): void;
139
141
  /** A primary click with Mod on a link. Without it, links don't open. */
@@ -152,7 +154,7 @@ export declare const editorEvents: readonly ["changed", "commandStateChanged", "
152
154
  * The editor. Create it with `InkKitEditor.mount`, load a document, and read it back with
153
155
  * `snapshot`. The reference is https://inkkit.cyzr.me/reference/editor.
154
156
  */
155
- export declare class InkKitEditor {
157
+ export declare class InkKitEditor<F extends DocumentFormat = TextDocumentFormat> {
156
158
  private readonly options;
157
159
  private editor;
158
160
  private readonly document;
@@ -201,6 +203,9 @@ export declare class InkKitEditor {
201
203
  private get generation();
202
204
  /** What `changed` reports for the document's new text. */
203
205
  private changeSnapshot;
206
+ private saved;
207
+ /** The current text, as `snapshot` checks and reads it. */
208
+ private savedText;
204
209
  /** Throws unless the document `captured` describes is still current, alive, not composing and
205
210
  * has no import pending. */
206
211
  private assertCaptured;
@@ -259,7 +264,8 @@ export declare class InkKitEditor {
259
264
  /** What the editor can do now, for enabling host controls. Unlike `snapshot`, it works during
260
265
  * composition. */
261
266
  commandState(expectedGeneration?: number): CommandState;
262
- /** An image adapter shows and exports an inserted reference, and so does a file adapter. */
267
+ /** An image adapter shows and exports an inserted reference, and so does a file adapter. An RTF
268
+ * document holds no images. */
263
269
  private get canInsertImages();
264
270
  private historyInputPlugin;
265
271
  private policyPlugin;
@@ -276,9 +282,15 @@ export declare class InkKitEditor {
276
282
  undo(expectedGeneration?: number): boolean;
277
283
  /** Returns whether a history step applied. */
278
284
  redo(expectedGeneration?: number): boolean;
279
- /** The complete current text, which is what a host saves. It throws rather than return partial
280
- * text. */
281
- snapshot(expectedGeneration?: number): DocumentSnapshot;
285
+ /** The complete current document, which is what a host saves. It throws rather than return a
286
+ * partial document. */
287
+ snapshot(expectedGeneration?: number): DocumentSnapshot<F>;
288
+ /**
289
+ * The loaded document converted to `format`, which must be offered, with what the conversion
290
+ * lost. It changes nothing: load the result as a new generation. Markdown converts to RTF and
291
+ * RTF to Markdown; the same format returns a copy. Throws `invalid-argument` for any other pair.
292
+ */
293
+ convertDocument(format: DocumentFormat, expectedGeneration?: number): ConvertedDocument;
282
294
  /** The whole document as standalone HTML for printing. Rejects rather than return partial
283
295
  * output. */
284
296
  printableSnapshot(expectedGeneration?: number): Promise<PrintableDocument>;
@@ -295,6 +307,8 @@ export declare class InkKitEditor {
295
307
  setCommentsVisible(visible: boolean): void;
296
308
  /** Inserts `text` literally at the selection and returns whether the document changed. */
297
309
  pasteAsPlainText(text: string, expectedGeneration?: number): boolean;
310
+ /** Whether an RTF edit that should have changed `before` was refused. */
311
+ private refusedRichEdit;
298
312
  private insertPlainText;
299
313
  /** Runs a table command and returns whether it applied. False in source and TXT modes, outside a
300
314
  * table for commands that need one, and at a boundary a move can't cross. */
@@ -310,17 +324,21 @@ export declare class InkKitEditor {
310
324
  private indentPlugin;
311
325
  private dispatchTransaction;
312
326
  /** Builds the editor in `root`. It has no document until `loadDocument`. Rejects with
313
- * `invalid-argument` for a bad root, handler or option. */
327
+ * `invalid-argument` for a bad root, handler or option. The editor's type follows `formats`:
328
+ * without `rtf` among them, its documents are text. */
329
+ static mount<F extends DocumentFormat>(root: HTMLElement, events: EditorEvents<F>, options: EditorOptions<F> & {
330
+ formats: readonly F[];
331
+ }): Promise<InkKitEditor<F>>;
314
332
  static mount(root: HTMLElement, events: EditorEvents, options?: EditorOptions): Promise<InkKitEditor>;
315
333
  /** Replaces the document. The generation must be greater than the loaded one. A failed load
316
334
  * changes nothing. */
317
- loadDocument(input: DocumentInput): void;
335
+ loadDocument(document: DocumentInput<F>): void;
318
336
  /** Moves focus off whichever of InkKit's text surfaces holds it; other focus is left alone. */
319
337
  private releaseFocus;
320
338
  /** Replaces the document with a newer version of it, keeping the selection, focus, scroll
321
339
  * position and Markdown editing mode. With `expectedGeneration`, the loaded document must be
322
340
  * that generation. */
323
- reloadDocument(input: DocumentInput, expectedGeneration?: number): void;
341
+ reloadDocument(document: DocumentInput<F>, expectedGeneration?: number): void;
324
342
  /** Names the scroll container and the host chrome that overlaps the editor. It replaces earlier
325
343
  * settings. */
326
344
  setViewport(options: ViewportOptions): void;
@@ -398,8 +416,8 @@ export declare class InkKitEditor {
398
416
  format(command: FormatCommand, options?: FormatOptions, expectedGeneration?: number): boolean;
399
417
  /**
400
418
  * Refuses a link destination that is empty, that opens anything but a web, mail or phone address
401
- * or a scheme the host listed, or that the Markdown writer cannot save so that it reads back the
402
- * same.
419
+ * or a scheme the host listed, or, in Markdown, that the writer cannot save so that it reads back
420
+ * the same. In RTF, it also refuses what the rich text link rule refuses.
403
421
  */
404
422
  private checkDestination;
405
423
  /**
@@ -0,0 +1,17 @@
1
+ import type { Ctx } from '@milkdown/kit/ctx';
2
+ import { type Slice, type Node as ProseNode } from '@milkdown/kit/prose/model';
3
+ import { type FormatLoss, type RichTextDocument } from '../types';
4
+ /** A formatted Markdown document as rich text, with what RTF could not hold. */
5
+ export declare function markdownToRichText(doc: ProseNode): {
6
+ document: RichTextDocument;
7
+ lost: readonly FormatLoss[];
8
+ };
9
+ /** A rich text document as Markdown, with what Markdown could not hold: alignment. Underline,
10
+ * superscript and subscript are written as `<u>`, `<sup>` and `<sub>`. */
11
+ export declare function richTextToMarkdown(ctx: Ctx, document: RichTextDocument): {
12
+ text: string;
13
+ lost: readonly FormatLoss[];
14
+ };
15
+ /** Markdown for content copied from a rich text document. Unlike a conversion it reports no
16
+ * losses and isn't read back: a copy may lose alignment. */
17
+ export declare function richContentMarkdown(ctx: Ctx, content: Slice): string;
@@ -1,6 +1,8 @@
1
1
  import type { DocumentFormat } from '../types';
2
2
  import type { FormatHandler } from './types';
3
- export type { FormatHandler, FormatSource, FormatOutput } from './types';
4
- /** Every format Inkkit can open, and the list a host is offered when it chooses none. */
5
- export declare const documentFormats: readonly ["md", "txt"];
3
+ export type { FormatHandler, FormatSource, FormatOutput, SavedText, } from './types';
4
+ /** Every format Inkkit can open. */
5
+ export declare const documentFormats: readonly ["md", "txt", "rtf"];
6
+ /** The formats a host is offered when it chooses none. */
7
+ export declare const defaultFormats: readonly ["md", "txt"];
6
8
  export declare const formatHandlers: Readonly<Record<DocumentFormat, FormatHandler>>;
@@ -0,0 +1,11 @@
1
+ import { Slice } from '@milkdown/kit/prose/model';
2
+ import type { EditorState } from '@milkdown/kit/prose/state';
3
+ import type { ClipboardInput, RichTextBlock } from '../types';
4
+ /** Blocks for pasted HTML. */
5
+ export declare function htmlBlocks(html: string, schemes: ReadonlySet<string>): RichTextBlock[];
6
+ /**
7
+ * The slice that `input` pastes into an RTF document at the selection. Explicit Markdown pastes as
8
+ * its text, unparsed; HTML keeps what RTF can hold; plain text gives a paragraph for each line.
9
+ * Plain text takes the marks of the text it replaces, as typing would.
10
+ */
11
+ export declare function richTextPaste(input: ClipboardInput, state: EditorState, schemes: ReadonlySet<string>): Slice;
@@ -0,0 +1,56 @@
1
+ import type { RichTextBlock, RichTextDocument, RichTextInline, RichTextMark } from '../types';
2
+ /** The deepest list nesting RTF can hold (`\ilvl` 0 to 8). */
3
+ export declare const maximumListDepth = 9;
4
+ /** The largest first number of an ordered list that RTF writes and reads back unchanged, as
5
+ * measured with the host's converter. */
6
+ export declare const maximumListStart = 2147483647;
7
+ /** Why a run cannot hold `text`, or undefined. Loading and editing share the rule. */
8
+ export declare function textProblem(text: string): string | undefined;
9
+ /** Why `href` cannot be a link's address, or undefined. Any address that is not empty and holds
10
+ * no control character is kept, as the host's converter keeps it; loading, editing, paste and the
11
+ * converter share the rule. Edits and paste also apply Inkkit's link safety. */
12
+ export declare function linkProblem(href: string): string | undefined;
13
+ /** The canonical order of marks. */
14
+ export declare const markRank: {
15
+ readonly bold: 0;
16
+ readonly italic: 1;
17
+ readonly underline: 2;
18
+ readonly strikethrough: 3;
19
+ readonly superscript: 4;
20
+ readonly subscript: 5;
21
+ readonly code: 6;
22
+ readonly link: 7;
23
+ };
24
+ type Path = string;
25
+ /** Collects inline content in canonical form: adjacent runs with equal marks merge, and each run
26
+ * is NFC after merging, because joining two NFC strings can leave a sequence that composes. */
27
+ export declare class InlineBuilder {
28
+ readonly content: RichTextInline[];
29
+ private marksKey?;
30
+ text(text: string, marks: readonly RichTextMark[]): void;
31
+ break(): void;
32
+ finish(): RichTextInline[];
33
+ }
34
+ /** Marks in canonical order. A link's run never also has underline: a link's underline is how it
35
+ * is drawn, so RTF readers report it on every link. */
36
+ export declare function canonicalMarks(marks: readonly RichTextMark[]): RichTextMark[];
37
+ /**
38
+ * Checks `value` as a version 1 document and returns its canonical form: marks sorted, a link's
39
+ * underline removed, adjacent equal runs merged, runs in NFC, and `start` of 1 left out. Throws
40
+ * `invalid-argument` naming the first problem, under `path`.
41
+ */
42
+ export declare function readRichTextDocument(value: unknown, path: Path): RichTextDocument;
43
+ /** The text that stands for a canonical document inside the editor: its JSON. Two documents are
44
+ * the same exactly when their texts are. */
45
+ export declare function richTextText(document: RichTextDocument): string;
46
+ /** The document a text from `richTextText` stands for, as a new object. */
47
+ export declare function richTextFromText(text: string): RichTextDocument;
48
+ /** Text from outside a document, such as a paste or another format, as canonical runs: a line or
49
+ * paragraph separator inside a paragraph becomes a line break, and characters RTF cannot hold as
50
+ * text become U+FFFD, so that no character disappears. */
51
+ export declare function appendText(builder: InlineBuilder, text: string, marks: readonly RichTextMark[]): void;
52
+ /** Typed or pasted text as paragraphs: each paragraph separator ends one, including a final one,
53
+ * so inserting `'a\n'` leaves the caret in a new paragraph. A line separator is a line break.
54
+ * Unlike the host's `RichTextDocument(plainText:)`, which reads a file, nothing is trimmed. */
55
+ export declare function textBlocks(text: string): RichTextBlock[];
56
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { Mark, Node as ProseNode, Schema } from '@milkdown/kit/prose/model';
2
+ import type { EditorState, Transaction } from '@milkdown/kit/prose/state';
3
+ import { type RichTextBlock, type RichTextDocument } from '../types';
4
+ /** The editor block for a rich text block. Its text also takes `around`, the marks of text that a
5
+ * paste replaces. */
6
+ export declare function proseBlock(schema: Schema, block: RichTextBlock, around?: readonly Mark[]): ProseNode;
7
+ /** The editor document for a canonical rich text document. */
8
+ export declare function richTextToProse(schema: Schema, document: RichTextDocument): ProseNode;
9
+ /** The canonical rich text document for an editor document. Throws `preservation` when the
10
+ * document holds something RTF cannot. The editor always holds a block, so its one empty
11
+ * paragraph is an empty document when `emptyAsNone`, as it is when the document loaded empty. */
12
+ export declare function proseToRichText(doc: ProseNode, emptyAsNone?: boolean): RichTextDocument;
13
+ /** Whether the document a transaction reaches holds only what RTF can, read in the part it
14
+ * changed and that part's ancestors. */
15
+ export declare function richTextAllows(tr: Transaction, before: EditorState): boolean;
16
+ /** The ranges of runs that have both a link and underline, which canonical form removes the
17
+ * underline from, in the part of `doc` from `from` to `to`. */
18
+ export declare function linkedUnderlines(doc: ProseNode, from: number, to: number): {
19
+ from: number;
20
+ to: number;
21
+ }[];
22
+ /** Whether every character from `from` to `to`, or the caret's marks, is in a link. */
23
+ export declare function inLink(state: EditorState): boolean;
@@ -0,0 +1,5 @@
1
+ import type { FormatHandler } from './types';
2
+ /** Rich text, which the host converts to and from RTF. The editor holds the canonical JSON as the
3
+ * document's text. It reaches no Markdown parsing or preservation;
4
+ * `test/formats/boundary.test.ts` checks its imports. */
5
+ export declare const richTextFormat: FormatHandler;
@@ -1,7 +1,34 @@
1
1
  import type { Ctx } from '@milkdown/kit/ctx';
2
- import type { Fragment, Node as ProseNode } from '@milkdown/kit/prose/model';
2
+ import type { Fragment, Node as ProseNode, Slice } from '@milkdown/kit/prose/model';
3
+ import type { EditorState, Transaction } from '@milkdown/kit/prose/state';
3
4
  import type { DiagramStore } from '../mermaid';
4
- import type { ClipboardInput, ClipboardOutput, DocumentContext, DocumentFormat, DocumentSnapshot, DocumentVersion, EditorLabels, FileAdapter, FormatPromise, ImageAdapter, PrintableDocument } from '../types';
5
+ import type { ClipboardInput, ClipboardOutput, DocumentContext, DocumentFormat, DocumentVersion, EditorLabels, FileAdapter, FormatPromise, ImageAdapter, PrintableDocument } from '../types';
6
+ /** The current document as the editor holds it: its text, which for RTF is the canonical JSON of
7
+ * its `RichTextDocument`. */
8
+ export interface SavedText extends DocumentVersion {
9
+ readonly format: DocumentFormat;
10
+ readonly text: string;
11
+ readonly dirty: boolean;
12
+ }
13
+ /** What a format whose document is not source text adds to formatted editing. */
14
+ export interface RichTextBehaviour {
15
+ /** Whether the document that `tr` reaches from `before` holds only what the format can. */
16
+ allows(tr: Transaction, before: EditorState): boolean;
17
+ /** Runs in `from` to `to` that hold both a link and underline, which the format cannot keep. */
18
+ linkedUnderlines(doc: ProseNode, from: number, to: number): {
19
+ from: number;
20
+ to: number;
21
+ }[];
22
+ /** Whether the selection is all link text, where underline does nothing. */
23
+ inLink(state: EditorState): boolean;
24
+ /** The slice a formatted paste inserts. */
25
+ paste(input: ClipboardInput, state: EditorState, linkSchemes: ReadonlySet<string>): Slice;
26
+ /** What copying the selection writes. */
27
+ copy(state: EditorState, linkSchemes: ReadonlySet<string>): {
28
+ text: string;
29
+ html: string;
30
+ };
31
+ }
5
32
  /** What a format keeps from reading a text, to save edits to the document it read. */
6
33
  export interface FormatSource {
7
34
  /** The document read from the text. */
@@ -23,6 +50,9 @@ export interface FormatOutput {
23
50
  context(): DocumentContext;
24
51
  diagrams(): DiagramStore;
25
52
  root(): HTMLElement;
53
+ /** Markdown for rich content copied from a document that is not Markdown. A copy may lose what
54
+ * Markdown can't hold, such as alignment. */
55
+ richTextMarkdown(content: Slice): string;
26
56
  remember<T extends {
27
57
  text: string;
28
58
  html: string;
@@ -30,7 +60,7 @@ export interface FormatOutput {
30
60
  }
31
61
  export type PrintableContent = Pick<PrintableDocument, 'html' | 'styles' | 'assets' | 'warnings'>;
32
62
  export interface PrintRequest {
33
- /** The snapshot's text. */
63
+ /** The current text. */
34
64
  readonly text: string;
35
65
  /** The document to print, which holds source typed but not yet settled. */
36
66
  readonly doc: ProseNode;
@@ -38,7 +68,7 @@ export interface PrintRequest {
38
68
  readonly output: FormatOutput;
39
69
  }
40
70
  export interface ClipboardRequest {
41
- readonly snapshot: DocumentSnapshot;
71
+ readonly snapshot: SavedText;
42
72
  /** The whole document, rather than the selection. */
43
73
  readonly all: boolean;
44
74
  readonly version: DocumentVersion;
@@ -61,6 +91,8 @@ export interface FormatHandler {
61
91
  readonly literalOnly: boolean;
62
92
  /** A source mode exists beside formatted mode. */
63
93
  readonly sourceMode: boolean;
94
+ /** The label that names the formatted surface. */
95
+ readonly formattedLabel: keyof Pick<EditorLabels, 'formattedEditor' | 'richTextEditor'>;
64
96
  /** The label that names the literal surface. */
65
97
  readonly literalLabel: keyof Pick<EditorLabels, 'plainTextEditor' | 'sourceEditor'>;
66
98
  /** `headings` lists the document's headings. */
@@ -70,6 +102,10 @@ export interface FormatHandler {
70
102
  /** Text inserted on the literal surface keeps its own line endings, rather than taking the
71
103
  * document's. */
72
104
  readonly keepsInsertedLineEndings: boolean;
105
+ /** Markdown input rules and bare-address links apply while typing in formatted mode. */
106
+ readonly markdownInput: boolean;
107
+ /** Present for a format that is not Markdown source but edits in formatted mode. */
108
+ readonly richText?: RichTextBehaviour;
73
109
  /** Reads loaded text into the formatted document. Throws when it cannot be shown. */
74
110
  load(ctx: Ctx, text: string): FormatSource;
75
111
  /** Reads text from the literal surface into the formatted document. */
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as registerDiagram, r as InkKitError, t as InkKitEditor } from "./chunks/core-DtLNFuDg.js";
1
+ import { n as registerDiagram, r as InkKitError, t as InkKitEditor } from "./chunks/core-Dl4jPn_d.js";
2
2
  //#region node_modules/.pnpm/dompurify@3.4.17/node_modules/dompurify/dist/purify.es.mjs
3
3
  /*! @license DOMPurify 3.4.17 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.17/LICENSE */
4
4
  function _OverloadYield(e, d) {
package/dist/types.d.ts CHANGED
@@ -1,5 +1,9 @@
1
- /** `md` is Markdown; `txt` is literal text, shown and saved as typed. */
2
- export type DocumentFormat = 'md' | 'txt';
1
+ /** `md` is Markdown; `txt` is literal text, shown and saved as typed; `rtf` is rich text, which the
2
+ * host converts to and from a `RichTextDocument`. */
3
+ export type DocumentFormat = 'md' | 'txt' | 'rtf';
4
+ /** The formats whose document is text: Markdown and TXT. An editor mounted without `rtf` in its
5
+ * `formats` has only these. */
6
+ export type TextDocumentFormat = 'md' | 'txt';
3
7
  /** What saving promises for a format. `exact` saves the file exactly. `structure` keeps the
4
8
  * structure and marks and replaces fonts, colors and sizes with Inkkit's style. `lossy` is a
5
9
  * conversion that drops something and says what. */
@@ -16,13 +20,87 @@ export interface DocumentContext {
16
20
  generation: number;
17
21
  operationId: string;
18
22
  }
19
- /** A document to load. `generation` must be greater than the loaded one. */
20
- export interface DocumentInput {
23
+ /** A document to load. `generation` must be greater than the loaded one. Markdown and TXT carry
24
+ * their `text`; RTF carries the `document` the host read from the file. `F` is the formats the
25
+ * editor was mounted with; without `rtf` among them, every input is text. */
26
+ export type DocumentInput<F extends DocumentFormat = TextDocumentFormat> = F extends 'rtf' ? RichTextDocumentInput : TextDocumentInput;
27
+ /** A Markdown or TXT document to load. */
28
+ export interface TextDocumentInput {
21
29
  documentId: string;
22
30
  generation: number;
23
- format: DocumentFormat;
31
+ format: TextDocumentFormat;
24
32
  text: string;
25
33
  }
34
+ /** An RTF document to load, as the host's converter read it. */
35
+ export interface RichTextDocumentInput {
36
+ documentId: string;
37
+ generation: number;
38
+ format: 'rtf';
39
+ document: RichTextDocument;
40
+ }
41
+ /** A rich text document: the JSON form of an RTF file that the host converts. Version 1 is the
42
+ * only version. */
43
+ export interface RichTextDocument {
44
+ version: 1;
45
+ blocks: RichTextBlock[];
46
+ }
47
+ /** A paragraph, a list or a table. A list item holds a paragraph and then only lists. */
48
+ export type RichTextBlock = {
49
+ type: 'paragraph';
50
+ /** Absent for left alignment. */
51
+ align?: 'center' | 'right' | 'justify';
52
+ content: RichTextInline[];
53
+ } | {
54
+ type: 'list';
55
+ ordered: boolean;
56
+ /** An ordered list's first number, 1 or more. Absent for 1. */
57
+ start?: number;
58
+ items: RichTextListItem[];
59
+ } | {
60
+ type: 'table';
61
+ /** Every row has the same number of cells. */
62
+ rows: RichTextTableCell[][];
63
+ };
64
+ export interface RichTextListItem {
65
+ blocks: RichTextBlock[];
66
+ }
67
+ export interface RichTextTableCell {
68
+ content: RichTextInline[];
69
+ }
70
+ /** A run of text, never empty and without line or paragraph separators, or a line break. */
71
+ export type RichTextInline = {
72
+ type: 'text';
73
+ text: string;
74
+ marks?: RichTextMark[];
75
+ } | {
76
+ type: 'break';
77
+ };
78
+ /** An inline mark. A run holds each type at most once, and never both superscript and
79
+ * subscript. */
80
+ export type RichTextMark = {
81
+ type: 'bold' | 'italic' | 'underline' | 'strikethrough' | 'superscript' | 'subscript' | 'code';
82
+ } | {
83
+ type: 'link';
84
+ href: string;
85
+ };
86
+ /** Something a conversion between formats could not keep. `count` is how many places lost it. */
87
+ export interface FormatLoss {
88
+ code: FormatLossCode;
89
+ count: number;
90
+ }
91
+ /** The closed list of what a conversion can lose. The API reference describes each one. */
92
+ export declare const formatLossCodes: readonly ['heading', 'code-block', 'diagram', 'quote', 'callout', 'task', 'rule', 'footnote', 'comment', 'highlight', 'image', 'file', 'wiki-link', 'literal', 'link', 'table-alignment', 'list-start', 'list-item-blocks', 'list-depth', 'link-underline', 'invalid-character', 'alignment', 'mark-spaces', 'empty-line'];
93
+ export type FormatLossCode = (typeof formatLossCodes)[number];
94
+ /** A document converted to another format, for the host to load as a new generation. */
95
+ export type ConvertedDocument = {
96
+ format: 'md' | 'txt';
97
+ text: string;
98
+ lost: readonly FormatLoss[];
99
+ } | {
100
+ format: 'rtf';
101
+ document: RichTextDocument;
102
+ lost: readonly FormatLoss[];
103
+ };
26
104
  /** Which document an output describes: the load, named by its generation, and the revision of
27
105
  * its content within that load. */
28
106
  export interface DocumentVersion {
@@ -30,8 +108,15 @@ export interface DocumentVersion {
30
108
  generation: number;
31
109
  revision: number;
32
110
  }
33
- /** The complete current text. `dirty` is true when it differs from the text of the last load. */
34
- export interface DocumentSnapshot extends DocumentInput, DocumentVersion {
111
+ /** The complete current document. `dirty` is true when it differs from the last load. `F` is the
112
+ * formats the editor was mounted with; without `rtf` among them, every snapshot is text. */
113
+ export type DocumentSnapshot<F extends DocumentFormat = TextDocumentFormat> = F extends 'rtf' ? RichTextDocumentSnapshot : TextDocumentSnapshot;
114
+ /** The complete current text of a Markdown or TXT document. */
115
+ export interface TextDocumentSnapshot extends TextDocumentInput, DocumentVersion {
116
+ dirty: boolean;
117
+ }
118
+ /** The complete current RTF document, in canonical form, for the host to write as RTF. */
119
+ export interface RichTextDocumentSnapshot extends RichTextDocumentInput, DocumentVersion {
35
120
  dirty: boolean;
36
121
  }
37
122
  /** The closed list of failure codes. The API reference describes each one. */
@@ -271,6 +356,8 @@ export interface EditorLabels {
271
356
  slashWarning: string;
272
357
  slashCaution: string;
273
358
  formattedEditor: string;
359
+ /** Accessible name of the formatted surface while an RTF document is loaded. */
360
+ richTextEditor: string;
274
361
  plainTextEditor: string;
275
362
  sourceEditor: string;
276
363
  placeholder: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicayzer/inkkit",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "description": "A preserving Markdown editor for offline web views and the web",
5
5
  "license": "MIT",
6
6
  "type": "module",