nuvra 0.4.0 → 0.5.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.
Files changed (57) hide show
  1. package/README.md +179 -13
  2. package/dist/compare.vue.d.ts +19 -0
  3. package/dist/components/document-editor.vue.d.ts +49 -3
  4. package/dist/components/editor-canvas.vue.d.ts +6 -7
  5. package/dist/components/editor-changes.vue.d.ts +18 -0
  6. package/dist/components/editor-comments.vue.d.ts +32 -0
  7. package/dist/components/editor-footnote-form.vue.d.ts +19 -0
  8. package/dist/components/editor-outline.vue.d.ts +16 -0
  9. package/dist/components/editor-slash-menu.vue.d.ts +13 -0
  10. package/dist/components/editor-toolbar.vue.d.ts +24 -1
  11. package/dist/core/comments.d.ts +26 -0
  12. package/dist/core/dates.d.ts +8 -0
  13. package/dist/core/diff.d.ts +11 -0
  14. package/dist/core/document-templates.d.ts +22 -0
  15. package/dist/core/docx/export.d.ts +19 -0
  16. package/dist/core/docx/import.d.ts +19 -0
  17. package/dist/core/docx/zip.d.ts +23 -0
  18. package/dist/core/engine/dom.d.ts +31 -1
  19. package/dist/core/engine/editing.d.ts +11 -0
  20. package/dist/core/engine/engine.d.ts +144 -2
  21. package/dist/core/engine/input-rules.d.ts +3 -1
  22. package/dist/core/engine/marks.d.ts +50 -1
  23. package/dist/core/engine/schema.d.ts +7 -2
  24. package/dist/core/export.d.ts +6 -5
  25. package/dist/core/footnotes.d.ts +15 -0
  26. package/dist/core/icons.d.ts +1 -1
  27. package/dist/core/labels.d.ts +6 -2
  28. package/dist/core/locales/uz-cyrl.d.ts +3 -0
  29. package/dist/core/locales/uz.d.ts +64 -1
  30. package/dist/core/numbers.d.ts +19 -0
  31. package/dist/core/outline.d.ts +42 -0
  32. package/dist/core/page.d.ts +12 -2
  33. package/dist/core/pagination.d.ts +4 -1
  34. package/dist/core/signature.d.ts +15 -0
  35. package/dist/core/slash-commands.d.ts +19 -0
  36. package/dist/core/templates.d.ts +32 -0
  37. package/dist/core/transliterate.d.ts +13 -0
  38. package/dist/core/types.d.ts +1 -1
  39. package/dist/core/ui-state.d.ts +8 -0
  40. package/dist/editor.vue.d.ts +6 -2
  41. package/dist/export-DhHI3ZrQ.js +94 -0
  42. package/dist/export-DhHI3ZrQ.js.map +1 -0
  43. package/dist/footnotes-DBShImw7.js +11 -0
  44. package/dist/footnotes-DBShImw7.js.map +1 -0
  45. package/dist/form.vue.d.ts +39 -0
  46. package/dist/index.d.ts +26 -1
  47. package/dist/index.js +8005 -4236
  48. package/dist/index.js.map +1 -1
  49. package/dist/{page-DL7Oj2o8.js → page-DY5fdgcT.js} +10 -10
  50. package/dist/page-DY5fdgcT.js.map +1 -0
  51. package/dist/style.css +1 -1
  52. package/dist/zip-CpbwZtot.js +46 -0
  53. package/dist/zip-CpbwZtot.js.map +1 -0
  54. package/package.json +5 -2
  55. package/dist/export-VeTfgCEp.js +0 -117
  56. package/dist/export-VeTfgCEp.js.map +0 -1
  57. package/dist/page-DL7Oj2o8.js.map +0 -1
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Writes the document as a real Word file (Office Open XML, `.docx`): paragraphs and headings with their alignment,
3
+ * indents and spacing, character formatting, links, lists, tables with merged cells, images, page breaks, the page
4
+ * setup, headers and footers with page fields, and the watermark.
5
+ */
6
+ import { type PageSettings } from '../page';
7
+ /** What the Word writer needs to know about the document. */
8
+ export interface DocxSource {
9
+ /** Clean document HTML as saved by the editor. */
10
+ html: string;
11
+ /** Document title, stored in the file properties and used by the `{title}` token. */
12
+ title: string;
13
+ /** Page size, orientation, margins, running texts and watermark. */
14
+ page: PageSettings;
15
+ }
16
+ /** MIME type of Word documents. */
17
+ export declare const DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
18
+ /** Builds a `.docx` file of the document. Images are embedded from data URLs or fetched from their address. */
19
+ export declare const buildDocx: ({ html, title, page }: DocxSource) => Promise<Blob>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Reads a Word document (`.docx`) into editor HTML: paragraphs and headings with alignment, indents and spacing,
3
+ * character formatting, links, lists, tables with merged cells, images, page breaks, the page setup and the header
4
+ * and footer texts. The result still passes through the editor's sanitiser.
5
+ */
6
+ import { type PageSettings } from '../page';
7
+ /** What was read from a Word document. */
8
+ export interface DocxImport {
9
+ /** Document content as HTML. */
10
+ html: string;
11
+ /** Page setup of the document's last section. */
12
+ page: PageSettings;
13
+ }
14
+ /**
15
+ * Reads a `.docx` file into editor HTML and page settings.
16
+ *
17
+ * @throws Error when the file is not a Word document.
18
+ */
19
+ export declare const readDocx: (data: ArrayBuffer | Uint8Array) => Promise<DocxImport>;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Minimal ZIP container support for Office documents, without dependencies: writing stores files uncompressed, which
3
+ * every ZIP reader (Word included) accepts; reading also inflates deflated entries with the browser's
4
+ * `DecompressionStream`.
5
+ */
6
+ /** A file inside a ZIP archive. */
7
+ export interface ZipEntry {
8
+ /** Path inside the archive, with forward slashes. */
9
+ name: string;
10
+ /** File content. */
11
+ data: Uint8Array;
12
+ }
13
+ /** CRC-32 checksum of the data. */
14
+ export declare const crc32: (data: Uint8Array) => number;
15
+ /** Packs files into an uncompressed ZIP archive. */
16
+ export declare const createZip: (entries: ZipEntry[]) => Uint8Array;
17
+ /**
18
+ * Reads every file of a ZIP archive. Stored and deflated entries are supported, which covers the files Office and
19
+ * other editors write.
20
+ *
21
+ * @throws Error when the data is not a ZIP archive or uses an unsupported compression method.
22
+ */
23
+ export declare const readZip: (buffer: ArrayBuffer | Uint8Array) => Promise<Map<string, Uint8Array>>;
@@ -3,6 +3,16 @@
3
3
  * the editor root, element factories and the small structural fixes (caret placeholders, mark merging) that keep the
4
4
  * editable markup predictable.
5
5
  */
6
+ /** Attribute naming the template variable of a variable chip. */
7
+ export declare const VARIABLE_ATTRIBUTE = "data-variable";
8
+ /** Selector for template variable chips: inline atoms that hold no text in the editor. */
9
+ export declare const VARIABLE_SELECTOR = "span[data-variable]";
10
+ /** Attribute holding the text of a footnote on its reference mark. */
11
+ export declare const FOOTNOTE_ATTRIBUTE = "data-footnote";
12
+ /** Selector for footnote references: inline atoms numbered by the editor, their note text in the attribute. */
13
+ export declare const FOOTNOTE_SELECTOR = "sup[data-footnote]";
14
+ /** Selector for every inline atom: elements inside a line that behave as one character and hold no editable text. */
15
+ export declare const INLINE_ATOM_SELECTOR = "span[data-variable], sup[data-footnote]";
6
16
  /** Selector for blocks without editable text inside: rules, images and page breaks. */
7
17
  export declare const ATOM_SELECTOR = "hr, img, div[data-type=\"page-break\"]";
8
18
  /** Selector for blocks that hold editable inline text. */
@@ -17,6 +27,12 @@ export declare const isText: (node: Node | null | undefined) => node is Text;
17
27
  export declare const isTextBlock: (node: Node | null | undefined) => node is HTMLElement;
18
28
  /** Whether the node is an ordered or unordered list. */
19
29
  export declare const isList: (node: Node | null | undefined) => node is HTMLElement;
30
+ /** Whether the node is a template variable chip. */
31
+ export declare const isVariable: (node: Node | null | undefined) => node is HTMLElement;
32
+ /** Whether the node is a footnote reference. */
33
+ export declare const isFootnote: (node: Node | null | undefined) => node is HTMLElement;
34
+ /** Whether the node is an inline atom: a variable chip or a footnote reference. */
35
+ export declare const isInlineAtom: (node: Node | null | undefined) => node is HTMLElement;
20
36
  /** Whether the node is a block without editable text (rule, image, page break). */
21
37
  export declare const isAtom: (node: Node | null | undefined) => node is HTMLElement;
22
38
  /** Whether the node is a `<br>`, placeholder or real. */
@@ -31,13 +47,25 @@ export declare const closestTag: (node: Node | null | undefined, root: HTMLEleme
31
47
  export declare const closestTextBlock: (node: Node | null | undefined, root: HTMLElement) => HTMLElement | null;
32
48
  /** Creates an element with attributes and children in one call. */
33
49
  export declare const createElement: <K extends keyof HTMLElementTagNameMap>(tag: K, attributes?: Record<string, string>, children?: Array<Node | string>) => HTMLElementTagNameMap[K];
50
+ /**
51
+ * Creates the chip of a template variable. It holds no text, so formatting and caret positions treat it as one
52
+ * character; its label is drawn by CSS from `data-label`, and serialising writes `{{name}}` into it.
53
+ */
54
+ export declare const createVariable: (name: string) => HTMLSpanElement;
55
+ /** Longest footnote text kept, in characters. */
56
+ export declare const MAX_FOOTNOTE_LENGTH = 2000;
57
+ /**
58
+ * Creates a footnote reference. Like a variable chip it holds no text in the editor: CSS draws its number, and
59
+ * serialising writes the number into it so saved HTML reads correctly anywhere.
60
+ */
61
+ export declare const createFootnote: (text: string) => HTMLElement;
34
62
  /** Creates the placeholder `<br>` that gives empty lines their height. */
35
63
  export declare const createTrailingBreak: () => HTMLBRElement;
36
64
  /** Creates a paragraph with the given inline content and the placeholder break it needs. */
37
65
  export declare const createParagraph: (children?: Node[]) => HTMLParagraphElement;
38
66
  /** Whether the element contains text, an image or a real line break. */
39
67
  export declare const hasVisibleContent: (element: Element) => boolean;
40
- /** Whether a text block has no text and no image, holding at most one break. */
68
+ /** Whether a text block has no text, image or inline atom, holding at most one break. */
41
69
  export declare const isEmptyTextBlock: (block: Element) => boolean;
42
70
  /**
43
71
  * Keeps exactly one placeholder `<br>` where the browser needs it: in empty blocks and after a user line break at the
@@ -56,6 +84,8 @@ export declare const mergeAdjacentMarks: (scope: HTMLElement) => void;
56
84
  export declare const textBlocksWithin: (scope: ParentNode) => HTMLElement[];
57
85
  /** Text blocks touched by the range, in document order. */
58
86
  export declare const textBlocksInRange: (root: HTMLElement, range: Range) => HTMLElement[];
87
+ /** Whether a range covers no text, image, variable or real line break. */
88
+ export declare const isVisuallyEmpty: (range: Range) => boolean;
59
89
  /** Whether nothing visible precedes the point inside its block. */
60
90
  export declare const isAtBlockStart: (block: HTMLElement, container: Node, offset: number) => boolean;
61
91
  /** Whether nothing visible follows the point inside its block. */
@@ -32,6 +32,17 @@ export declare const splitAtCaret: (root: HTMLElement, range: Range) => Caret |
32
32
  export declare const insertLineBreak: (root: HTMLElement, range: Range) => Caret | null;
33
33
  /** Inserts plain text at a collapsed range, creating a paragraph if the caret sits between blocks. */
34
34
  export declare const insertTextAtCaret: (root: HTMLElement, range: Range, text: string) => Caret;
35
+ /**
36
+ * Inserts an inline atom (a variable chip or a footnote reference) at a collapsed range, creating a paragraph if the caret sits between
37
+ * blocks. Code blocks hold plain text only, so nothing is inserted there.
38
+ * @returns the caret right after the element, or `null` when it could not be inserted.
39
+ */
40
+ export declare const insertInlineAtCaret: (root: HTMLElement, range: Range, element: HTMLElement) => Caret | null;
41
+ /**
42
+ * Inline atom (variable chip or footnote reference) right before (`backward`) or right after the collapsed caret, with
43
+ * nothing visible in between, so Backspace and Delete remove it as one character in every browser.
44
+ */
45
+ export declare const adjacentInlineAtom: (root: HTMLElement, range: Range, backward: boolean) => HTMLElement | null;
35
46
  /**
36
47
  * Pastes sanitised blocks at a collapsed range. A single paragraph flows into the current line; several blocks
37
48
  * split the current block, with the first and last pasted paragraphs merging into its halves as in Word.
@@ -1,3 +1,5 @@
1
+ import { type OutlineHeading } from '../outline';
2
+ import { type TransliterationDirection } from '../transliterate';
1
3
  import { type EditorUiState } from '../ui-state';
2
4
  import { type HeadingTag, type ParagraphIndents, type SpacingSide, type TextAlign, type TextDirection } from './blocks';
3
5
  import { EditorHistory } from './history';
@@ -5,6 +7,19 @@ import { type ListKind } from './lists';
5
7
  import { type MarkName, type StyleName, type TextCase } from './marks';
6
8
  import { SearchController, type SearchState } from './search';
7
9
  import { type TableCell } from './tables';
10
+ /** A tracked insertion or deletion; the parts of one edit are joined. */
11
+ export interface TrackedChange {
12
+ /** Id shared by the parts of the edit. */
13
+ id: string;
14
+ /** Whether text was inserted or deleted. */
15
+ type: 'insert' | 'delete';
16
+ /** Name of the author; may be empty. */
17
+ author: string;
18
+ /** When the change was made, as an ISO 8601 string. */
19
+ time: string;
20
+ /** Inserted or deleted text. */
21
+ text: string;
22
+ }
8
23
  /** Settings the host component passes when it creates the engine. */
9
24
  interface DocumentEngineOptions {
10
25
  /** Initial HTML; it is sanitised before it reaches the DOM. */
@@ -17,6 +32,11 @@ interface DocumentEngineOptions {
17
32
  placeholder: () => string;
18
33
  /** Receives image files pasted or dropped into the document; the selection is already at the target. */
19
34
  onImageFiles: (files: File[]) => void;
35
+ /**
36
+ * Label a template variable chip shows, or `undefined` for a name the host does not know. Called on every refresh,
37
+ * so labels follow the host's variable list and locale; typed `{{name}}` becomes a chip only for known names.
38
+ */
39
+ variableLabel?: (name: string) => string | undefined;
20
40
  }
21
41
  /** Events emitted by the engine, mapped to their payloads. */
22
42
  interface EngineEvents {
@@ -100,6 +120,10 @@ export declare class DocumentEngine {
100
120
  private selectedImageElement;
101
121
  /** Formatting the format painter carries until it is painted onto a selection. */
102
122
  private painterFormat;
123
+ /** Author of tracked changes while changes are tracked, otherwise `null`. */
124
+ private trackingAuthor;
125
+ /** Change the running typing group adds to, so typed characters form one insertion. */
126
+ private typingChange;
103
127
  /**
104
128
  * Takes over `root` as the editable document, loads the initial content and starts listening to its events.
105
129
  *
@@ -173,7 +197,7 @@ export declare class DocumentEngine {
173
197
  private currentRange;
174
198
  /** Captures the document markup and selection for the undo history. */
175
199
  private snapshot;
176
- /** Updates the placeholder state and search results, then notifies listeners. */
200
+ /** Updates the placeholder state, variable labels and search results, then notifies listeners. */
177
201
  private refresh;
178
202
  /**
179
203
  * Runs one edit as an undo step, then normalises the document and restores the selection by text position.
@@ -187,12 +211,38 @@ export declare class DocumentEngine {
187
211
  private finishEdit;
188
212
  /** Records an undo step for a change that does not depend on the selection (checkboxes, image attributes). */
189
213
  private mutate;
190
- /** Deletes the selected content, if any, and returns a collapsed range where it started. */
214
+ /**
215
+ * Deletes the selected content, if any, and returns a collapsed range where the new content goes: where the selection
216
+ * started, or after the text marked as deleted while changes are tracked.
217
+ */
191
218
  private collapsedAfterDelete;
192
219
  /** Deletes the selection as one undo step and leaves a collapsed caret where it started. */
193
220
  private deleteSelection;
221
+ /** Whether edits are recorded as tracked changes. */
222
+ get tracksChanges(): boolean;
223
+ /** Starts or stops recording typing, deleting and pasting as tracked changes by `author`. */
224
+ setTrackChanges(enabled: boolean, author?: string): void;
225
+ /** A change mark for the next edit; typing keeps adding to one change until the caret moves. */
226
+ private nextChange;
227
+ /**
228
+ * Marks a range as deleted and returns a caret at its start or after it. A marker element keeps the end position
229
+ * while own insertions inside the range are removed for real.
230
+ */
231
+ private deleteTracked;
232
+ /** Moves a caret that sits inside deleted text to its end, so new text never becomes part of a deletion. */
233
+ private outsideDeletion;
234
+ /** Marks the text between two document positions as inserted by the tracking author. */
235
+ private markInsertedBetween;
236
+ /** Tracked insertions and deletions in document order, the parts of one edit grouped by id and kind. */
237
+ getChanges(): TrackedChange[];
238
+ /** Accepts (`true`) or rejects the tracked changes with the given id, or every change without one, as an undo step. */
239
+ resolveChanges(accept: boolean, id?: string): void;
240
+ /** Selects the text of a tracked change and scrolls it into view. */
241
+ selectChange(id: string): void;
194
242
  /** Number of characters in the document text. */
195
243
  private characterCount;
244
+ /** Text of every block as the document reads once its tracked changes are accepted: deleted text is left out. */
245
+ private blockTexts;
196
246
  /** Whether adding `extra` characters would exceed the configured maximum length. */
197
247
  private exceedsLimit;
198
248
  /** Remembers the selection; a selection moved by the user drops pending formatting and ends the typing group. */
@@ -206,6 +256,13 @@ export declare class DocumentEngine {
206
256
  private handleTextInput;
207
257
  /** Deletes selections and joins blocks at their edges itself; single characters are deleted natively. */
208
258
  private handleDeleteInput;
259
+ /**
260
+ * Marks the character, word or line next to the caret as deleted. Text that is already marked as deleted is
261
+ * stepped over, as in Word, instead of being deleted again.
262
+ */
263
+ private deleteTrackedAtCaret;
264
+ /** The range from a caret to the next character, word or line boundary in one direction. */
265
+ private extendCaret;
209
266
  /** Repairs the structure after a native edit and applies Markdown and typography rules to typed text. */
210
267
  private onInput;
211
268
  /** Browsers occasionally leave text outside paragraphs or a <div> after native edits; fix it in place. */
@@ -260,6 +317,13 @@ export declare class DocumentEngine {
260
317
  private restoreSnapshot;
261
318
  /** Inserts plain text at the selection, replacing selected content and applying pending formatting. */
262
319
  insertText(text: string): void;
320
+ /** Text of the current block before a collapsed caret, or `null` when the selection is not a caret in text. */
321
+ getTextBeforeCaret(): string | null;
322
+ /**
323
+ * Deletes the characters right before a collapsed caret, as one undo step; used by typed triggers such as the
324
+ * `/` command menu to remove what was typed.
325
+ */
326
+ deleteBeforeCaret(count: number): void;
263
327
  /** Formatting at the start of a range, or `null` when the text there is unformatted. */
264
328
  private captureFormat;
265
329
  /**
@@ -277,6 +341,15 @@ export declare class DocumentEngine {
277
341
  private setPending;
278
342
  /** Changes the letter case of the selected text. */
279
343
  changeTextCase(mode: TextCase): void;
344
+ /** Converts Uzbek text between the Latin and Cyrillic alphabet: the selection, or the whole document at a caret. */
345
+ transliterate(direction: TransliterationDirection): void;
346
+ /**
347
+ * Rewrites the amount that is selected, or the number right before the caret, with `format`; used to add an amount
348
+ * in words. Nothing changes when the text there is not an amount.
349
+ *
350
+ * @returns whether an amount was found and rewritten.
351
+ */
352
+ replaceAmount(format: (value: number) => string): boolean;
280
353
  /** Stores the format the painter carries and shows the painting cursor while it does. */
281
354
  private setPainterFormat;
282
355
  /**
@@ -308,6 +381,11 @@ export declare class DocumentEngine {
308
381
  setTextDirection(direction: TextDirection): void;
309
382
  /** Turns the selected blocks into a list of the given kind, converts another list kind, or lifts them out. */
310
383
  toggleList(kind: ListKind): void;
384
+ /**
385
+ * Switches the numbered list at the selection, together with its nested lists, between simple (1, 2, 3) and legal
386
+ * (1.1, 1.2) numbering. The setting lives on the outermost numbered list.
387
+ */
388
+ setListNumbering(style: 'default' | 'legal'): void;
311
389
  /** List items are nested or lifted; other paragraphs get indentation steps. */
312
390
  indent(direction: 1 | -1): void;
313
391
  /**
@@ -319,6 +397,70 @@ export declare class DocumentEngine {
319
397
  insertHorizontalRule(): void;
320
398
  /** Inserts a manual page break. */
321
399
  insertPageBreak(): void;
400
+ /**
401
+ * Inserts sanitised HTML at the selection as one undo step. By default it flows into the current line the way pasting
402
+ * does; with `asBlocks` the content starts on a line of its own after a non-empty paragraph, as prepared fragments
403
+ * such as signature blocks and document templates should.
404
+ */
405
+ insertContent(html: string, { asBlocks }?: {
406
+ asBlocks?: boolean | undefined;
407
+ }): void;
408
+ /** Headings written directly in the document, in document order, down to the given level. */
409
+ getOutline(depth?: number): OutlineHeading[];
410
+ /** Whether the document has a table of contents. */
411
+ get hasTableOfContents(): boolean;
412
+ /**
413
+ * Writes a table of contents: an existing one is replaced in place, keeping the selection, otherwise the table is
414
+ * inserted at the selection. Without `addToHistory` a replacement joins the previous undo step, e.g. when page
415
+ * numbers are corrected right after inserting the table.
416
+ */
417
+ setTableOfContents(html: string, { addToHistory }?: {
418
+ addToHistory?: boolean | undefined;
419
+ }): void;
420
+ /** Scrolls a heading to the top of the view and puts the caret at its start. */
421
+ goToHeading(heading: HTMLElement): void;
422
+ /**
423
+ * Inserts a footnote reference with its text at the selection, replacing selected content, as one undo step.
424
+ * @returns the new reference, or `null` when nothing could be inserted (for example in a code block).
425
+ */
426
+ insertFootnote(text: string): HTMLElement | null;
427
+ /** Changes the text of a footnote as one undo step; unchanged text records nothing. */
428
+ setFootnoteText(reference: HTMLElement, text: string): void;
429
+ /** Removes a footnote reference together with its note, as one undo step. */
430
+ removeFootnote(reference: HTMLElement): void;
431
+ /** Footnote references with their texts, in document order; the first one is number 1. */
432
+ getFootnotes(): Array<{
433
+ element: HTMLElement;
434
+ text: string;
435
+ }>;
436
+ /**
437
+ * Anchors a new comment to the selected text as one undo step.
438
+ * @returns whether text was selected and the id is valid.
439
+ */
440
+ addComment(id: string): boolean;
441
+ /** Removes the anchors of a comment, keeping their text, as one undo step. */
442
+ removeComment(id: string): void;
443
+ /** Ids of the comments anchored in the document, each once, in document order. */
444
+ getCommentIds(): string[];
445
+ /** Ids of the comments anchored around the caret or the start of the selection, innermost first. */
446
+ getCommentsAtSelection(): string[];
447
+ /** Selects the text of a comment and scrolls it into view. */
448
+ selectComment(id: string): void;
449
+ /**
450
+ * Shows resolved comments without their highlight and marks the active one. Only classes change, which saved HTML
451
+ * drops, so this is neither an edit nor an undo step.
452
+ */
453
+ decorateComments(resolved: ReadonlySet<string>, active: string | null): void;
454
+ /** Anchor elements of one comment, in document order. */
455
+ private commentAnchors;
456
+ /** Inserts the chip of a template variable at the selection; invalid names are ignored. */
457
+ insertVariable(name: string): void;
458
+ /** Names of the template variables used in the document, each once, in document order. */
459
+ getVariables(): string[];
460
+ /** Re-reads the labels of every variable chip, e.g. after the host's variable list or locale changed. */
461
+ refreshVariables(): void;
462
+ /** Writes the host's label into every chip that shows a different one; a chip of an unknown name shows `{{name}}`. */
463
+ private updateVariableLabels;
322
464
  /** Link that contains the start of the selection. */
323
465
  getActiveLink(): HTMLAnchorElement | null;
324
466
  /**
@@ -12,6 +12,8 @@ type InputRule = () => InputRuleResult;
12
12
  /**
13
13
  * Looks for a rule completed by the character that was just typed. The returned function performs the change,
14
14
  * so the caller can record an undo step first. Rules never apply inside code.
15
+ *
16
+ * @param isKnownVariable Whether a typed `{{name}}` names a template variable of the editor.
15
17
  */
16
- export declare const matchInputRule: (root: HTMLElement, range: Range, typed: string) => InputRule | null;
18
+ export declare const matchInputRule: (root: HTMLElement, range: Range, typed: string, isKnownVariable?: (name: string) => boolean) => InputRule | null;
17
19
  export {};
@@ -35,7 +35,49 @@ export declare const setHighlight: (root: HTMLElement, range: Range, color: stri
35
35
  export declare const setLink: (root: HTMLElement, range: Range, href: string, target: string | null) => boolean;
36
36
  /** Removes links from the selected text, keeping the text itself. */
37
37
  export declare const unsetLink: (root: HTMLElement, range: Range) => void;
38
- /** Removes every mark, span style, highlight and link from the selected text. */
38
+ /** Attribute holding the id of the comment a span of text is anchored to. */
39
+ export declare const COMMENT_ATTRIBUTE = "data-comment";
40
+ /** A valid comment id: letters, digits, `_` and `-`. */
41
+ export declare const COMMENT_ID: RegExp;
42
+ /** Selector of every comment anchor. */
43
+ export declare const COMMENT_SELECTOR = "span[data-comment]";
44
+ /**
45
+ * Anchors a comment to the selected text. Text that already belongs to another comment keeps it, so comments may
46
+ * overlap.
47
+ * @returns whether any text was selected.
48
+ */
49
+ export declare const addCommentAnchor: (root: HTMLElement, range: Range, id: string) => boolean;
50
+ /** Attribute holding the id of a tracked change; inserted and deleted text of one edit share it. */
51
+ export declare const CHANGE_ATTRIBUTE = "data-change";
52
+ /** A valid change id. */
53
+ export declare const CHANGE_ID: RegExp;
54
+ /** Selector of every tracked insertion and deletion. */
55
+ export declare const CHANGE_SELECTOR = "ins[data-change], del[data-change]";
56
+ /** Who made a tracked change and when, written on its `<ins>` or `<del>`. */
57
+ export interface ChangeMark {
58
+ /** Id shared by the parts of one edit. */
59
+ id: string;
60
+ /** Name of the author; may be empty. */
61
+ author: string;
62
+ /** When the change was made, as an ISO 8601 string. */
63
+ time: string;
64
+ }
65
+ /** Tracked deletion around `node`, if any. */
66
+ export declare const deletionAncestor: (node: Node, root: HTMLElement) => HTMLElement | null;
67
+ /** Marks the text and inline atoms of a range as inserted, unless they already are. */
68
+ export declare const markInserted: (root: HTMLElement, range: Range, mark: ChangeMark) => void;
69
+ /**
70
+ * Deletes a range the tracked way: text the same author inserted while tracking is removed for real, other text is
71
+ * marked as deleted and stays visible until the deletion is accepted.
72
+ * @returns whether anything was selected.
73
+ */
74
+ export declare const markDeleted: (root: HTMLElement, range: Range, mark: ChangeMark) => boolean;
75
+ /**
76
+ * Accepts or rejects tracked changes: accepting keeps inserted text and drops deleted text, rejecting does the
77
+ * opposite. Blocks left empty by removed text are kept, like Word keeps the paragraph.
78
+ */
79
+ export declare const resolveChanges: (elements: HTMLElement[], accept: boolean) => void;
80
+ /** Removes every mark, span style, highlight and link from the selected text; comment anchors and changes stay. */
39
81
  export declare const clearMarks: (root: HTMLElement, range: Range) => void;
40
82
  /** Letter case transformations offered by the toolbar. */
41
83
  export type TextCase = 'upper' | 'lower' | 'title' | 'sentence' | 'toggle';
@@ -46,6 +88,13 @@ export type TextCase = 'upper' | 'lower' | 'title' | 'sentence' | 'toggle';
46
88
  * @returns whether any text was selected.
47
89
  */
48
90
  export declare const applyTextCase: (root: HTMLElement, range: Range, mode: TextCase) => boolean;
91
+ /**
92
+ * Rewrites the selected text node by node, so every mark around it stays; each call also receives the character
93
+ * before the node in the same block, so rules that depend on word boundaries work across formatting.
94
+ *
95
+ * @returns whether any text was selected.
96
+ */
97
+ export declare const transformSelectedText: (root: HTMLElement, range: Range, transform: (text: string, previous: string) => string) => boolean;
49
98
  /** Which marks apply to `node`. */
50
99
  export declare const readMarks: (root: HTMLElement, node: Node) => Record<MarkName, boolean>;
51
100
  /** Value of a span style at `node`, or an empty string when none is set. */
@@ -1,3 +1,7 @@
1
+ /** A valid template variable name: letters, digits, `_`, `.` and `-`, as used in `{{name}}`. */
2
+ export declare const VARIABLE_NAME: RegExp;
3
+ /** Attribute holding the label a variable chip shows in the editor; editor-only. */
4
+ export declare const VARIABLE_LABEL_ATTRIBUTE = "data-label";
1
5
  /** Attribute pagination writes on blocks it moved to the next sheet; editor-only. */
2
6
  export declare const GAP_ATTRIBUTE = "data-doc-gap";
3
7
  /** Class marking table cells in a drag selection; editor-only. */
@@ -32,9 +36,10 @@ export declare const normalizeContainer: (container: ParentNode & Node, isRoot?:
32
36
  export declare const sanitizeHtml: (html: string) => DocumentFragment;
33
37
  /**
34
38
  * Removes editor-only markup (pagination gaps, cell selection). With `forExport` it also drops caret placeholders
35
- * and editing attributes, which history snapshots keep so the restored DOM is immediately editable.
39
+ * and editing attributes, which history snapshots keep so the restored DOM is immediately editable, and numbers the
40
+ * footnote references from `firstFootnote` (a sheet of a longer document continues the numbering).
36
41
  */
37
- export declare const cleanEditorArtifacts: (scope: Element | DocumentFragment, forExport: boolean) => void;
42
+ export declare const cleanEditorArtifacts: (scope: Element | DocumentFragment, forExport: boolean, firstFootnote?: number) => void;
38
43
  /** Clean HTML of the editor content, as stored in the model and exported. */
39
44
  export declare const serialize: (root: HTMLElement) => string;
40
45
  /** Whether the document is a single unformatted, empty paragraph. */
@@ -1,3 +1,4 @@
1
+ import { type SheetFootnote } from './footnotes';
1
2
  import { type PageSettings } from './page';
2
3
  /** Everything needed to print or export the document. */
3
4
  interface DocumentSnapshot {
@@ -8,6 +9,8 @@ interface DocumentSnapshot {
8
9
  * with real page numbers and breaks the pages exactly where the editor shows them.
9
10
  */
10
11
  pages?: string[];
12
+ /** Footnotes of every sheet of `pages`; without pages, the notes of all of them are printed after the document. */
13
+ footnotes?: SheetFootnote[][];
11
14
  /** Document title, used for the print title and file names. */
12
15
  title: string;
13
16
  /** Page size, orientation, margins and the running texts. */
@@ -21,11 +24,9 @@ export declare const toFileName: (title: string) => string;
21
24
  * the pages break where the editor shows them; without them the document flows and the browser repeats one fixed
22
25
  * header and footer on every page.
23
26
  */
24
- export declare const buildPrintableHtml: ({ html, pages, title, page }: DocumentSnapshot) => string;
25
- /** Word opens HTML saved with the Office namespaces as a regular document in print layout. */
26
- export declare const buildWordHtml: ({ html, title, page }: DocumentSnapshot) => string;
27
- /** Offers text content as a file download. */
28
- export declare const downloadFile: (content: string, fileName: string, type: string) => void;
27
+ export declare const buildPrintableHtml: ({ html, pages, footnotes, title, page }: DocumentSnapshot) => string;
28
+ /** Offers text or binary content as a file download. */
29
+ export declare const downloadFile: (content: string | Blob, fileName: string, type: string) => void;
29
30
  /** Prints through a detached iframe so the application chrome never ends up on paper. Waits for images first. */
30
31
  export declare const printHtml: (documentHtml: string) => void;
31
32
  export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The notes of footnotes as they are drawn at the bottom of a sheet. The editor, the layout measurement and printing
3
+ * all render them with this markup, so the space pagination reserves matches what is drawn.
4
+ */
5
+ /** A footnote as it appears at the bottom of a sheet. */
6
+ export interface SheetFootnote {
7
+ /** Number of the footnote in the document, starting at 1. */
8
+ number: number;
9
+ /** Text of the note. */
10
+ text: string;
11
+ }
12
+ /** Class of the notes block; its look is defined in `document-content.css`. */
13
+ export declare const FOOTNOTES_CLASS = "doc-footnotes";
14
+ /** HTML of the notes block of one sheet, or an empty string when the sheet has no footnotes. */
15
+ export declare const footnotesHtml: (notes: readonly SheetFootnote[]) => string;
@@ -3,7 +3,7 @@
3
3
  * from Lucide 1.44.0 (https://lucide.dev, ISC license, see LICENSE); the data is generated, not edited by hand.
4
4
  */
5
5
  /** Name of an icon in the editor's set. */
6
- export type IconName = 'a-arrow-down' | 'a-arrow-up' | 'between-horizontal-end' | 'between-horizontal-start' | 'between-vertical-end' | 'between-vertical-start' | 'bold' | 'calendar-days' | 'case-sensitive' | 'chevron-down' | 'chevron-right' | 'chevron-up' | 'clipboard' | 'code' | 'columns-2' | 'copy' | 'ellipsis' | 'external-link' | 'file-code' | 'file-down' | 'file-sliders' | 'file-text' | 'file-type' | 'grid-2x2-x' | 'grid-3x3' | 'highlighter' | 'image-plus' | 'italic' | 'languages' | 'link' | 'list' | 'list-indent-decrease' | 'list-indent-increase' | 'list-ordered' | 'list-todo' | 'loader-circle' | 'maximize-2' | 'minimize-2' | 'minus' | 'move-horizontal' | 'omega' | 'paintbrush' | 'panel-top' | 'panel-top-dashed' | 'pencil' | 'pilcrow' | 'pilcrow-left' | 'pilcrow-right' | 'plus' | 'printer' | 'quote' | 'rectangle-horizontal' | 'rectangle-vertical' | 'redo-2' | 'remove-formatting' | 'rows-2' | 'ruler' | 'scissors' | 'scroll-text' | 'search' | 'separator-horizontal' | 'square-code' | 'square-split-vertical' | 'strikethrough' | 'subscript' | 'superscript' | 'table-cells-merge' | 'table-cells-split' | 'text-align-center' | 'text-align-end' | 'text-align-justify' | 'text-align-start' | 'text-cursor-input' | 'trash' | 'underline' | 'undo-2' | 'unfold-vertical' | 'unlink' | 'upload' | 'whole-word' | 'x';
6
+ export type IconName = 'a-arrow-down' | 'a-arrow-up' | 'banknote' | 'between-horizontal-end' | 'between-horizontal-start' | 'between-vertical-end' | 'between-vertical-start' | 'bold' | 'braces' | 'calendar-days' | 'case-sensitive' | 'check' | 'chevron-down' | 'chevron-right' | 'chevron-up' | 'clipboard' | 'code' | 'columns-2' | 'copy' | 'ellipsis' | 'external-link' | 'file-code' | 'file-down' | 'file-sliders' | 'file-text' | 'file-type' | 'grid-2x2-x' | 'grid-3x3' | 'highlighter' | 'image-plus' | 'italic' | 'languages' | 'link' | 'list' | 'list-checks' | 'list-indent-decrease' | 'list-indent-increase' | 'list-ordered' | 'list-todo' | 'loader-circle' | 'maximize-2' | 'message-square' | 'message-square-plus' | 'minimize-2' | 'minus' | 'move-horizontal' | 'omega' | 'paintbrush' | 'panel-left' | 'panel-top' | 'panel-top-dashed' | 'pencil' | 'pilcrow' | 'pilcrow-left' | 'pilcrow-right' | 'plus' | 'printer' | 'quote' | 'rectangle-horizontal' | 'rectangle-vertical' | 'redo-2' | 'remove-formatting' | 'reply' | 'rows-2' | 'ruler' | 'scissors' | 'scroll-text' | 'search' | 'separator-horizontal' | 'signature' | 'square-code' | 'square-split-vertical' | 'strikethrough' | 'subscript' | 'superscript' | 'table-cells-merge' | 'table-cells-split' | 'table-of-contents' | 'text-align-center' | 'text-align-end' | 'text-align-justify' | 'text-align-start' | 'text-cursor-input' | 'trash' | 'underline' | 'undo-2' | 'unfold-vertical' | 'unlink' | 'upload' | 'whole-word' | 'x';
7
7
  /** One SVG element of an icon: its tag and attributes. */
8
8
  export type IconElement = readonly [tag: string, attributes: Readonly<Record<string, string | number>>];
9
9
  /** Elements of every icon, by name. */
@@ -1,7 +1,7 @@
1
1
  import { type EditorLabelKey } from './locales/uz';
2
2
  export type { EditorLabelKey };
3
- /** Languages the editor interface is available in. */
4
- export type EditorLocaleCode = 'uz' | 'en' | 'ru';
3
+ /** Languages the editor interface is available in: Uzbek in Latin and Cyrillic script, English and Russian. */
4
+ export type EditorLocaleCode = 'uz' | 'uz-Cyrl' | 'en' | 'ru';
5
5
  /**
6
6
  * A built-in interface language. Locales only select one of the translations shipped with the editor; the texts
7
7
  * themselves cannot be changed from outside.
@@ -16,6 +16,8 @@ export interface EditorLocale {
16
16
  export type EditorLocaleInput = EditorLocale | EditorLocaleCode;
17
17
  /** Uzbek (Latin) interface. */
18
18
  export declare const uzLocale: EditorLocale;
19
+ /** Uzbek (Cyrillic) interface. */
20
+ export declare const uzCyrlLocale: EditorLocale;
19
21
  /** English interface. */
20
22
  export declare const enLocale: EditorLocale;
21
23
  /** Russian interface. */
@@ -35,4 +37,6 @@ export declare const formatShortcut: (shortcut: string) => string;
35
37
  export declare const useEditorLabels: (locale?: () => EditorLocaleInput | undefined) => {
36
38
  t: (key: EditorLabelKey, named?: Record<string, unknown>) => string;
37
39
  withShortcut: (key: EditorLabelKey, shortcut: string) => string;
40
+ /** Code of the editor's language, e.g. for numbers and dates written into the document. */
41
+ locale: import("vue").ComputedRef<EditorLocaleCode>;
38
42
  };
@@ -0,0 +1,3 @@
1
+ import type { EditorLabelKey } from './uz';
2
+ /** Uzbek (Cyrillic) texts of the editor interface, generated by `scripts/generate-uz-cyrl.mjs`. */
3
+ export declare const uzCyrl: Readonly<Record<EditorLabelKey, string>>;