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
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # nuvra
2
2
 
3
3
  Word-style document editor for Vue 3. A real page view with paper sizes and margins, a lighter web view for
4
- forms, tables, images, lists, find & replace, HTML source mode, printing and export to HTML or Word (`.doc`).
4
+ forms, tables, images, lists, find & replace, comments, HTML source mode, printing, export to HTML and Word files
5
+ (`.docx`) you can open again.
5
6
 
6
7
  **[Documentation and live demo →](https://nuvra-docs.vercel.app)**
7
8
 
@@ -17,6 +18,11 @@ forms, tables, images, lists, find & replace, HTML source mode, printing and exp
17
18
  the editor shows them, and the Word export uses Word's own header, footer and page fields.
18
19
  - A ruler above the page for the margins and for the first line, left and right indents of a paragraph.
19
20
  - A page watermark such as DRAFT or COPY, drawn behind the text of every page and carried into print, HTML and Word.
21
+ - Real `.docx` export and import, multilevel (1.1.1) numbering, a table of contents and a navigation pane.
22
+ - Footnotes at the bottom of their page, carried into print and Word.
23
+ - Comments with replies, tracked changes that round-trip with Word, a comparison of two versions, and templates
24
+ filled in as a form.
25
+ - A `/` command menu and a toolbar slot for your own commands and buttons.
20
26
 
21
27
  ## Installation
22
28
 
@@ -91,7 +97,10 @@ const uploadImage: DocumentImageUploadHandler = async file => {
91
97
  | Prop | Type | Default | Description |
92
98
  | ----------------- | --------------------------------- | -------- | -------------------------------------------------------------------------- |
93
99
  | `v-model` | `string` | `''` | Document HTML; an empty document is an empty string. |
94
- | `v-model:page` | `PageSettings` | A4 | Paper size, orientation and margins. |
100
+ | `v-model:page` | `PageSettings` | A4 | Paper size, orientation, margins, headers, footers, watermark, numbering. |
101
+ | `v-model:comments`| `DocumentComment[]` | — | Comments; binding it turns the comment tools on. |
102
+ | `v-model:trackChanges` | `boolean` | `false` | Records edits as tracked changes. |
103
+ | `author` | `string` | `''` | Name written on new comments, replies and tracked changes. |
95
104
  | `autofocus` | `boolean` | `false` | Places the caret at the end of the document once ready. |
96
105
  | `canvasPadding` | `number \| string` | `50` | Gray space around the page or web sheet. |
97
106
  | `defaultViewMode` | `'page' \| 'web'` | `'page'` | View shown first. |
@@ -103,10 +112,14 @@ const uploadImage: DocumentImageUploadHandler = async file => {
103
112
  | `maxImageSizeMb` | `number` | `10` | Largest accepted image file. |
104
113
  | `maxLength` | `number` | `0` | Character limit; `0` means unlimited. |
105
114
  | `placeholder` | `string` | `''` | Text shown while the document is empty. |
115
+ | `ruler` | `boolean` | `true` | Shows the ruler in the page view. |
116
+ | `slashCommands` | `SlashCommand[]` | `[]` | Your own commands, listed first in the `/` menu. |
106
117
  | `title` | `string` | `''` | Print title and exported file name. |
107
118
  | `uploadImage` | `(file: File) => Promise<string>` | — | Uploads an image and resolves with its URL. |
119
+ | `variables` | `TemplateVariable[]` | `[]` | Template variables the user can insert. |
108
120
 
109
- `Editor` accepts the same props except `v-model:page`, `defaultViewMode`, `height` and `title`.
121
+ `Editor` accepts the same props except `v-model:page`, `v-model:comments`, `v-model:trackChanges`, `author`,
122
+ `defaultViewMode`, `height`, `ruler`, `slashCommands` and `title`.
110
123
 
111
124
  Numbers are pixels; strings are used as CSS lengths (`'100%'`, `'50vh'`).
112
125
 
@@ -117,29 +130,182 @@ Numbers are pixels; strings are used as CSS lengths (`'100%'`, `'50vh'`).
117
130
  | `focus` | — | The document received focus. |
118
131
  | `blur` | — | The document lost focus; the model is up to date. |
119
132
  | `uploadError` | `error: unknown` | An image was rejected or its upload failed. |
133
+ | `importError` | `error: unknown` | A Word file could not be read. |
120
134
 
121
135
  ### Exposed methods (`DocumentEditor` ref)
122
136
 
123
- | Method | Description |
124
- | -------------- | ---------------------------------------------------------------- |
125
- | `focus()` | Moves keyboard focus into the document. |
126
- | `getHTML()` | Returns the document HTML, including edits not yet in the model. |
127
- | `print()` | Opens the browser print dialog. |
128
- | `exportHtml()` | Downloads the document as an HTML page. |
129
- | `exportWord()` | Downloads the document as a Word-compatible `.doc` file. |
130
- | `engine` | The editing engine, for advanced integrations. |
137
+ | Method | Description |
138
+ | ------------------------- | ---------------------------------------------------------------- |
139
+ | `focus()` | Moves keyboard focus into the document. |
140
+ | `getHTML()` | Returns the document HTML, including edits not yet in the model. |
141
+ | `insertVariable(name)` | Inserts a template variable at the selection. |
142
+ | `updateTableOfContents()` | Inserts or refreshes the table of contents. |
143
+ | `importWord(file)` | Replaces the document with the content of a `.docx` file. |
144
+ | `print()` | Opens the browser print dialog. |
145
+ | `exportHtml()` | Downloads the document as an HTML page. |
146
+ | `exportWord()` | Downloads the document as a Word file (`.docx`). |
147
+ | `engine` | The editing engine (`DocumentEngine`), for advanced integrations. |
131
148
 
132
149
  ### Keyboard shortcuts
133
150
 
134
151
  `Ctrl/⌘+B`, `I`, `U` — bold, italic, underline · `Ctrl/⌘+Shift+H` — highlight · `Ctrl/⌘+Z`, `Ctrl/⌘+Shift+Z` — undo,
135
- redo · `Ctrl/⌘+F` — find · `Ctrl/⌘+H` — replace · `Ctrl/⌘+K` — link · `Ctrl/⌘+P` — print.
152
+ redo · `Ctrl/⌘+F` — find · `Ctrl/⌘+H` — replace · `Ctrl/⌘+K` — link · `Ctrl/⌘+Alt+M` — comment · `Ctrl/⌘+P` — print.
136
153
 
137
154
  The full list, with Markdown-like input rules, is in the
138
155
  [keyboard shortcuts guide](https://nuvra-docs.vercel.app/docs/keyboard-shortcuts).
139
156
 
157
+ ## Templates and signatures
158
+
159
+ Pass `variables` to let users insert template variables with the toolbar's **{ }** menu or by typing `{{name}}`.
160
+ They are saved as `<span data-variable="name">{{name}}</span>`; `fillTemplate` replaces them with escaped values,
161
+ in the browser or on a Node server:
162
+
163
+ ```ts
164
+ import { type TemplateVariable, fillTemplate } from 'nuvra';
165
+
166
+ const variables: TemplateVariable[] = [
167
+ { name: 'full_name', label: 'Full name' },
168
+ { name: 'letter_date', label: 'Letter date' }
169
+ ];
170
+
171
+ const letter = fillTemplate(template, { full_name: 'Aziz Karimov', letter_date: '14.09.2026' });
172
+ ```
173
+
174
+ The pen button inserts a signature block in the editor's language: a signature line, an “Approved” or “Agreed”
175
+ block, or the signatures of both parties of a contract. It is a borderless table, so it prints and exports to Word
176
+ without lines.
177
+
178
+ The document button inserts ready-made templates (official letter, order, application, certificate, act), and the
179
+ toolbar writes amounts in words (`15 000 000 (o‘n besh million)`), inserts long dates (`2026-yil 14-sentabr`) and
180
+ converts Uzbek text between the Latin and Cyrillic alphabets. The same helpers are exported: `getDocumentTemplate`,
181
+ `numberToWords`, `formatAmountInWords`, `parseAmount`, `formatLongDate` and `transliterate`.
182
+
183
+ ### Filling a template as a form
184
+
185
+ `DocumentForm` shows a saved template as it will be printed, with an input in place of every variable. Fields of the
186
+ same variable share one value:
187
+
188
+ ```vue
189
+ <script setup lang="ts">
190
+ import { ref } from 'vue';
191
+ import { DocumentForm } from 'nuvra';
192
+
193
+ const values = ref<Record<string, string>>({});
194
+ const form = ref<InstanceType<typeof DocumentForm>>();
195
+
196
+ const submit = () => {
197
+ if (form.value?.validate().length) return; // empty fields are marked and focused
198
+ const html = form.value?.getHTML(); // filled with fillTemplate
199
+ };
200
+ </script>
201
+
202
+ <template>
203
+ <DocumentForm ref="form" v-model="values" :template="template" :variables="variables" />
204
+ </template>
205
+ ```
206
+
207
+ ## Word files and long documents
208
+
209
+ "Download as Word (.docx)" in the "More" menu writes a real Office Open XML file with the page setup, headers and
210
+ footers with page fields, the watermark, lists, tables with merged cells, images, footnotes and tracked changes as
211
+ Word revisions. "Open Word file (.docx)" (or `importWord(file)`) loads one into the editor, footnotes and revisions
212
+ included; a file that cannot be read emits `importError`. `buildDocx` and `readDocx` do the same in your own code. A
213
+ document with several sections gets the page setup of its last section, and the content of a different first page
214
+ header is not imported.
215
+
216
+ ### Footnotes
217
+
218
+ "Footnote" in the insert menu or the `/` menu adds a numbered reference and opens a small form for the note; clicking
219
+ a reference edits or deletes it. A footnote is saved in the reference, `<sup data-footnote="note text">1</sup>`, and
220
+ renumbered in document order. The page view draws the notes at the bottom of the sheet the reference is on, the web
221
+ view after the document; printing follows the sheets, and the Word export writes Word footnotes. Notes are plain text.
222
+ From code: `engine.insertFootnote(text)`, `setFootnoteText(element, text)`, `removeFootnote(element)`,
223
+ `getFootnotes()`.
224
+
225
+ For long documents the toolbar offers multilevel numbering (1., 1.1., 1.1.1., saved as `<ol data-numbering="legal">`),
226
+ a table of contents of the headings with page numbers (saved as `<table data-type="toc">`, refreshed with
227
+ `updateTableOfContents()`), and a navigation pane. `PageSettings` has `differentFirstPage` to hide the header, footer
228
+ and page number on the first page, and `firstPageNumber` for the number printed on it.
229
+
230
+ ## Comments, tracked changes and comparison
231
+
232
+ Bind `v-model:comments` to turn comments on. The HTML keeps only the anchors, `<span data-comment="id">`; the
233
+ comments are plain data you store next to the document:
234
+
235
+ ```vue
236
+ <script setup lang="ts">
237
+ import { ref } from 'vue';
238
+ import { DocumentEditor, type DocumentComment } from 'nuvra';
239
+
240
+ const html = ref('');
241
+ const comments = ref<DocumentComment[]>([]);
242
+
243
+ const save = () =>
244
+ fetch('/api/documents/42', {
245
+ method: 'PUT',
246
+ headers: { 'Content-Type': 'application/json' },
247
+ body: JSON.stringify({ html: html.value, comments: comments.value })
248
+ });
249
+ </script>
250
+
251
+ <template>
252
+ <DocumentEditor v-model="html" v-model:comments="comments" author="Aziz Karimov" @blur="save" />
253
+ </template>
254
+ ```
255
+
256
+ Users select text and press "Add comment" (`Ctrl/⌘+Alt+M`); the "Comments" panel replies, resolves, reopens and
257
+ deletes them, and flags comments whose text was deleted.
258
+
259
+ ### Tracked changes
260
+
261
+ Bind `v-model:trackChanges` (or press "Track changes") to record typing, deleting, cut and paste as tracked changes
262
+ by `author`. They are part of the HTML, `<ins data-change="id" data-author="…" data-time="…">` and `<del …>`, shown
263
+ and printed green-underlined and red-struck. The "Changes" panel accepts or rejects them one by one or all at once;
264
+ from code use `engine.getChanges()`, `engine.resolveChanges(accept, id?)` and `engine.selectChange(id)`. Formatting,
265
+ block changes (headings, lists, tables), Enter and joining paragraphs are not tracked. The Word export writes them as
266
+ revisions and the import reads Word revisions back.
267
+
268
+ ```vue
269
+ <DocumentEditor v-model="html" v-model:track-changes="tracking" author="Aziz Karimov" />
270
+ ```
271
+
272
+ `DocumentCompare` shows what changed between two versions: inserted words in green, deleted words struck through in
273
+ red. Unchanged blocks stay as they are, changed paragraphs are compared word by word, and added or removed blocks are
274
+ shown whole. `compareDocuments(before, after)` returns the same HTML and counts for your own view.
275
+
276
+ ```vue
277
+ <DocumentCompare :before="previousVersion" :after="html" :height="600" />
278
+ ```
279
+
280
+ ## Commands and toolbar buttons
281
+
282
+ Typing `/` at the start of a line or after a space opens a command menu: headings, lists, table, page break, footnote,
283
+ table of contents, dates, signature blocks and your variables. `slashCommands` adds your own commands at the top, and the
284
+ `toolbar` slot adds your own buttons:
285
+
286
+ ```vue
287
+ <script setup lang="ts">
288
+ import { DocumentEditor, type SlashCommand } from 'nuvra';
289
+
290
+ const slashCommands: SlashCommand[] = [
291
+ { id: 'director', label: 'Director’s name', icon: 'pencil', run: engine => engine.insertText('A. Karimov') }
292
+ ];
293
+ </script>
294
+
295
+ <template>
296
+ <DocumentEditor v-model="html" :slash-commands="slashCommands">
297
+ <template #toolbar="{ engine, disabled }">
298
+ <button type="button" class="doc-tb-button" :disabled="disabled" @mousedown.prevent @click="engine.insertText('✓')">
299
+
300
+ </button>
301
+ </template>
302
+ </DocumentEditor>
303
+ </template>
304
+ ```
305
+
140
306
  ## Languages
141
307
 
142
- The interface ships in Uzbek (`uz`, the default), English (`en`) and Russian (`ru`). The translations are part of
308
+ The interface ships in Uzbek (`uz`, the default), Uzbek Cyrillic (`uzCyrl`), English (`en`) and Russian (`ru`). The translations are part of
143
309
  the package and cannot be changed from outside; an app only picks the language.
144
310
 
145
311
  For one editor, pass the locale (or just its code) to the `locale` prop:
@@ -0,0 +1,19 @@
1
+ import { type EditorLocaleInput } from './core/labels';
2
+ import './styles/document-content.css';
3
+ import './styles/editor-ui.css';
4
+ interface Props {
5
+ /** HTML of the earlier version. */
6
+ before: string;
7
+ /** HTML of the later version. */
8
+ after: string;
9
+ /** Interface language: a built-in locale or its code; defaults to the app-wide language. */
10
+ locale?: EditorLocaleInput;
11
+ /** Height of the component, in pixels or any CSS length; `'auto'` grows with the document. */
12
+ height?: number | string;
13
+ }
14
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
15
+ height: number | string;
16
+ locale: EditorLocaleInput;
17
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -1,7 +1,11 @@
1
+ import { type DocumentComment } from '../core/comments';
1
2
  import { DocumentEngine } from '../core/engine/engine';
2
3
  import { type EditorLocaleInput } from '../core/labels';
3
4
  import { type DocumentViewMode, type PageSettings } from '../core/page';
5
+ import type { SlashCommand } from '../core/slash-commands';
6
+ import type { TemplateVariable } from '../core/templates';
4
7
  import type { DocumentImageUploadHandler } from '../core/types';
8
+ import { type EditorUiState } from '../core/ui-state';
5
9
  import '../styles/document-content.css';
6
10
  import '../styles/editor-ui.css';
7
11
  /** A CSS length: numbers are pixels, strings are used as written (for example, `'100%'` or `'auto'`). */
@@ -11,6 +15,8 @@ interface Props {
11
15
  autofocus?: boolean;
12
16
  /** Gray space around the page or web sheet that separates the document from the editor frame. */
13
17
  canvasPadding?: CssSize;
18
+ /** Name written as the author of new comments, replies and tracked changes. */
19
+ author?: string;
14
20
  /** View shown first; form fields use the lighter web view. */
15
21
  defaultViewMode?: DocumentViewMode;
16
22
  /** Makes the document read-only and disables every editing control. */
@@ -29,22 +35,41 @@ interface Props {
29
35
  minHeight?: CssSize;
30
36
  /** Text shown while the document is empty; falls back to the translated default placeholder. */
31
37
  placeholder?: string;
38
+ /** Commands of the host application, listed first in the `/` menu. */
39
+ slashCommands?: readonly SlashCommand[];
32
40
  /** Shows the ruler above the sheet in the page view; users can also toggle it in the document menu. */
33
41
  ruler?: boolean;
34
42
  /** Used as the print title and the exported file name. */
35
43
  title?: string;
36
44
  /** Uploads an inserted image and resolves with its URL; without it images are embedded as data URLs. */
37
45
  uploadImage?: DocumentImageUploadHandler;
46
+ /** Template variables the user can insert; typing `{{name}}` of one of them inserts it as well. */
47
+ variables?: readonly TemplateVariable[];
38
48
  }
39
49
  type __VLS_Props = Props;
50
+ type __VLS_Slots = {
51
+ /**
52
+ * Buttons of the host application, placed at the start of the toolbar's right-hand group. `engine` runs editing
53
+ * commands, `state` describes the formatting at the caret and `disabled` tells whether editing is possible.
54
+ */
55
+ toolbar?: (props: {
56
+ engine: DocumentEngine;
57
+ state: EditorUiState;
58
+ disabled: boolean;
59
+ }) => unknown;
60
+ };
40
61
  type __VLS_ModelProps = {
41
62
  /** Document HTML. An empty document is written as an empty string; typing updates it after a short delay. */
42
63
  modelValue?: string;
43
64
  /** Paper size, orientation, and margins used by the page view, printing, and export. */
44
65
  'page'?: PageSettings;
66
+ /** Whether edits are recorded as tracked changes; the toolbar can switch it. */
67
+ 'trackChanges'?: boolean;
68
+ /** Comments on the document; binding it turns the comment tools on. The HTML keeps only their anchors. */
69
+ 'comments'?: DocumentComment[] | undefined;
45
70
  };
46
71
  type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
47
- declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
72
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
48
73
  /** The editing engine, for advanced integrations. */
49
74
  engine: import("vue").ShallowRef<DocumentEngine | null, DocumentEngine | null>;
50
75
  /** Downloads the document as an HTML page. */
@@ -55,6 +80,12 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
55
80
  focus: () => void | undefined;
56
81
  /** Returns the document HTML, including edits not yet written to the model. */
57
82
  getHTML: () => string;
83
+ /** Replaces the document with the content and page setup of a `.docx` file. */
84
+ importWord: (file: File) => Promise<void>;
85
+ /** Inserts the chip of a template variable at the selection. */
86
+ insertVariable: (name: string) => void | undefined;
87
+ /** Inserts the table of contents at the selection, or refreshes the existing one. */
88
+ updateTableOfContents: () => Promise<void>;
58
89
  /** Opens the print dialog. */
59
90
  print: () => Promise<void>;
60
91
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -62,28 +93,43 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
62
93
  blur: () => any;
63
94
  "update:page": (value: PageSettings) => any;
64
95
  uploadError: (error: unknown) => any;
96
+ importError: (error: unknown) => any;
65
97
  "update:modelValue": (value: string) => any;
98
+ "update:trackChanges": (value: boolean) => any;
99
+ "update:comments": (value: DocumentComment[] | undefined) => any;
66
100
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
67
101
  onFocus?: (() => any) | undefined;
68
102
  onBlur?: (() => any) | undefined;
69
103
  "onUpdate:page"?: ((value: PageSettings) => any) | undefined;
70
104
  onUploadError?: ((error: unknown) => any) | undefined;
105
+ onImportError?: ((error: unknown) => any) | undefined;
71
106
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
107
+ "onUpdate:trackChanges"?: ((value: boolean) => any) | undefined;
108
+ "onUpdate:comments"?: ((value: DocumentComment[] | undefined) => any) | undefined;
72
109
  }>, {
73
110
  title: string;
74
111
  height: CssSize;
112
+ locale: EditorLocaleInput;
75
113
  ruler: boolean;
76
114
  placeholder: string;
77
115
  disabled: boolean;
78
116
  minHeight: CssSize;
79
- maxLength: number;
80
117
  maxHeight: CssSize;
118
+ maxLength: number;
119
+ variables: readonly TemplateVariable[];
120
+ author: string;
81
121
  autofocus: boolean;
82
122
  canvasPadding: CssSize;
83
123
  defaultViewMode: DocumentViewMode;
84
- locale: EditorLocaleInput;
85
124
  maxImageSizeMb: number;
125
+ slashCommands: readonly SlashCommand[];
86
126
  uploadImage: DocumentImageUploadHandler;
87
127
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
128
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
88
129
  declare const _default: typeof __VLS_export;
89
130
  export default _default;
131
+ type __VLS_WithSlots<T, S> = T & {
132
+ new (): {
133
+ $slots: S;
134
+ };
135
+ };
@@ -1,6 +1,7 @@
1
1
  import type { ParagraphIndents } from '../core/engine/blocks';
2
2
  import type { DocumentEngine } from '../core/engine/engine';
3
- import { type DocumentViewMode, type PageHeaderFooter, type PageMargins, type PageMetrics, type PageWatermark } from '../core/page';
3
+ import { type SheetFootnote } from '../core/footnotes';
4
+ import { type DocumentViewMode, type PageMargins, type PageMetrics, type PageSettings } from '../core/page';
4
5
  interface Props {
5
6
  /** Grow with the content between the editor's min and max height instead of filling a fixed height. */
6
7
  autoHeight: boolean;
@@ -10,10 +11,10 @@ interface Props {
10
11
  documentTitle: string;
11
12
  /** Engine working on the editable element; `null` until the parent has created it. */
12
13
  engine: DocumentEngine | null;
13
- /** Text repeated in the bottom margin of every sheet. */
14
- footer?: PageHeaderFooter;
15
- /** Text repeated in the top margin of every sheet. */
16
- header?: PageHeaderFooter;
14
+ /** Footnotes of every sheet, drawn at its bottom; the web view shows all of them after the document. */
15
+ footnotes: SheetFootnote[][];
16
+ /** Page setup: running texts, watermark and page numbering of every sheet. */
17
+ page: PageSettings;
17
18
  /** Indents of the paragraph at the caret, shown by the ruler. */
18
19
  indents: ParagraphIndents;
19
20
  /** Page size and margins in pixels. */
@@ -24,8 +25,6 @@ interface Props {
24
25
  rulerVisible: boolean;
25
26
  /** Paginated sheets or a single web sheet. */
26
27
  viewMode: DocumentViewMode;
27
- /** Watermark drawn behind the text of every sheet. */
28
- watermark?: PageWatermark;
29
28
  /** Zoom in percent. */
30
29
  zoom: number;
31
30
  }
@@ -0,0 +1,18 @@
1
+ import type { TrackedChange } from '../core/engine/engine';
2
+ interface Props {
3
+ /** Tracked changes in document order. */
4
+ changes: readonly TrackedChange[];
5
+ /** Read-only document: changes can be reviewed but not accepted or rejected. */
6
+ readonly: boolean | undefined;
7
+ }
8
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ select: (id: string) => any;
10
+ close: () => any;
11
+ resolve: (accept: boolean, id?: string | undefined) => any;
12
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
13
+ onSelect?: ((id: string) => any) | undefined;
14
+ onClose?: (() => any) | undefined;
15
+ onResolve?: ((accept: boolean, id?: string | undefined) => any) | undefined;
16
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
+ declare const _default: typeof __VLS_export;
18
+ export default _default;
@@ -0,0 +1,32 @@
1
+ import type { DocumentComment } from '../core/comments';
2
+ interface Props {
3
+ /** Comments in document order. */
4
+ comments: ReadonlyArray<DocumentComment>;
5
+ /** Ids of the comments whose text is still in the document. */
6
+ anchored: ReadonlySet<string>;
7
+ /** Comment at the caret, highlighted in the list. */
8
+ activeId: string | null;
9
+ /** Whether the form of a new comment is shown. */
10
+ drafting: boolean;
11
+ /** Read-only document: comments can be read but not changed. */
12
+ readonly: boolean | undefined;
13
+ }
14
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ select: (id: string) => any;
16
+ reply: (id: string, text: string) => any;
17
+ close: () => any;
18
+ remove: (id: string) => any;
19
+ resolve: (id: string, resolved: boolean) => any;
20
+ add: (text: string) => any;
21
+ cancelDraft: () => any;
22
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
23
+ onSelect?: ((id: string) => any) | undefined;
24
+ onReply?: ((id: string, text: string) => any) | undefined;
25
+ onClose?: (() => any) | undefined;
26
+ onRemove?: ((id: string) => any) | undefined;
27
+ onResolve?: ((id: string, resolved: boolean) => any) | undefined;
28
+ onAdd?: ((text: string) => any) | undefined;
29
+ onCancelDraft?: (() => any) | undefined;
30
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
31
+ declare const _default: typeof __VLS_export;
32
+ export default _default;
@@ -0,0 +1,19 @@
1
+ interface Props {
2
+ /** The footnote reference being edited. */
3
+ reference: HTMLElement;
4
+ /** Element the form is positioned in; it must be positioned itself. */
5
+ container: HTMLElement;
6
+ /** Read-only document: the note is shown but cannot be changed. */
7
+ readonly: boolean | undefined;
8
+ }
9
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
+ cancel: () => any;
11
+ remove: () => any;
12
+ save: (text: string) => any;
13
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
14
+ onCancel?: (() => any) | undefined;
15
+ onRemove?: (() => any) | undefined;
16
+ onSave?: ((text: string) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import type { OutlineHeading } from '../core/outline';
2
+ interface Props {
3
+ /** Headings of the document with the page each starts on, `null` outside the page view. */
4
+ headings: ReadonlyArray<OutlineHeading & {
5
+ page: number | null;
6
+ }>;
7
+ }
8
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ select: (heading: HTMLElement) => any;
10
+ close: () => any;
11
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
12
+ onSelect?: ((heading: HTMLElement) => any) | undefined;
13
+ onClose?: (() => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import type { DocumentEngine } from '../core/engine/engine';
2
+ import { type SlashCommand } from '../core/slash-commands';
3
+ interface Props {
4
+ /** Engine the commands run on. */
5
+ engine: DocumentEngine;
6
+ /** Every command the menu offers. */
7
+ commands: readonly SlashCommand[];
8
+ /** Element the menu is positioned in; it must be positioned itself. */
9
+ container: HTMLElement;
10
+ }
11
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
@@ -1,5 +1,6 @@
1
1
  import type { DocumentEngine } from '../core/engine/engine';
2
2
  import { type PageSettings } from '../core/page';
3
+ import type { TemplateVariable } from '../core/templates';
3
4
  import type { DocumentMenuAction } from '../core/types';
4
5
  import { type EditorUiState } from '../core/ui-state';
5
6
  interface Props {
@@ -13,6 +14,16 @@ interface Props {
13
14
  fullscreen: boolean;
14
15
  /** Whether the formatting marks (pilcrows) are shown in the document. */
15
16
  marksVisible: boolean;
17
+ /** Whether the navigation panel with the headings is open. */
18
+ outlineVisible: boolean;
19
+ /** Whether the host keeps comments (`v-model:comments`); the comment buttons are hidden otherwise. */
20
+ commentsEnabled: boolean;
21
+ /** Whether the comments panel is open. */
22
+ commentsVisible: boolean;
23
+ /** Whether edits are recorded as tracked changes. */
24
+ trackChanges: boolean;
25
+ /** Whether the tracked changes panel is open. */
26
+ changesVisible: boolean;
16
27
  /** Current page settings, edited in the page setup popover. */
17
28
  page: PageSettings;
18
29
  /** Whether the ruler is shown above the sheet. */
@@ -23,8 +34,14 @@ interface Props {
23
34
  state: EditorUiState;
24
35
  /** Whether images are being uploaded, shown on the upload button. */
25
36
  uploading: boolean;
37
+ /** Template variables offered by the variable menu; the menu is hidden without any. */
38
+ variables: ReadonlyArray<TemplateVariable>;
26
39
  }
27
- declare const __VLS_export: import("vue").DefineComponent<Props, {
40
+ declare var __VLS_604: {};
41
+ type __VLS_Slots = {} & {
42
+ default?: (props: typeof __VLS_604) => any;
43
+ };
44
+ declare const __VLS_base: import("vue").DefineComponent<Props, {
28
45
  /** Opens the link popover. */
29
46
  openLink: () => void;
30
47
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -38,5 +55,11 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {
38
55
  onInsertImages?: ((files: File[]) => any) | undefined;
39
56
  "onUpdate:page"?: ((page: PageSettings) => any) | undefined;
40
57
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
58
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
41
59
  declare const _default: typeof __VLS_export;
42
60
  export default _default;
61
+ type __VLS_WithSlots<T, S> = T & {
62
+ new (): {
63
+ $slots: S;
64
+ };
65
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Comments on parts of a document. The document HTML only keeps the anchors, `<span data-comment="id">`; the comments
3
+ * themselves are plain data the host stores next to the document with `v-model:comments`.
4
+ */
5
+ /** A reply in the thread of a comment. */
6
+ export interface DocumentCommentReply {
7
+ /** Unique id of the reply. */
8
+ id: string;
9
+ /** Text of the reply. */
10
+ text: string;
11
+ /** Name of the person who wrote it, when the host knows it. */
12
+ author?: string;
13
+ /** When it was written, as an ISO 8601 string. */
14
+ createdAt: string;
15
+ }
16
+ /** A comment anchored to a span of the document text. */
17
+ export interface DocumentComment extends DocumentCommentReply {
18
+ /** Whether the discussion is closed; resolved comments keep their anchor but are not highlighted. */
19
+ resolved?: boolean;
20
+ /** Replies in the order they were written. */
21
+ replies?: DocumentCommentReply[];
22
+ }
23
+ /** A new random id for a comment or a reply, usable as an HTML attribute value. */
24
+ export declare const createCommentId: () => string;
25
+ /** Comments in the order their anchors appear in the document; comments whose text was deleted come last. */
26
+ export declare const sortComments: (comments: readonly DocumentComment[], anchoredIds: readonly string[]) => DocumentComment[];
@@ -0,0 +1,8 @@
1
+ import type { NumberWordsLocale } from './numbers';
2
+ /** A date as `dd.mm.yyyy`, the short form of Uzbek and Russian documents. */
3
+ export declare const formatShortDate: (date: Date) => string;
4
+ /**
5
+ * A date written out as official documents do: `2026-yil 14-sentabr`, `2026 йил 14 сентябрь`, `14 сентября 2026 г.`
6
+ * or `14 September 2026`.
7
+ */
8
+ export declare const formatLongDate: (date: Date, locale?: NumberWordsLocale) => string;
@@ -0,0 +1,11 @@
1
+ /** What changed between two versions. */
2
+ export interface DocumentComparison {
3
+ /** Display HTML of the new version with insertions and deletions marked. */
4
+ html: string;
5
+ /** Number of inserted words, and of words in inserted blocks. */
6
+ insertions: number;
7
+ /** Number of deleted words, and of words in deleted blocks. */
8
+ deletions: number;
9
+ }
10
+ /** Compares two versions of a document and marks what was inserted and deleted in the new one. */
11
+ export declare const compareDocuments: (before: string, after: string) => DocumentComparison;
@@ -0,0 +1,22 @@
1
+ import type { EditorLabelKey, EditorLocaleCode } from './labels';
2
+ import type { TemplateVariable } from './templates';
3
+ /** Built-in document templates. */
4
+ export type DocumentTemplateId = 'letter' | 'order' | 'application' | 'certificate' | 'act';
5
+ /** A document template ready to be inserted into the editor. */
6
+ export interface DocumentTemplate {
7
+ /** Template identifier. */
8
+ id: DocumentTemplateId;
9
+ /** Document HTML with template variables. */
10
+ html: string;
11
+ /** Variables the template uses, with labels in the requested language. */
12
+ variables: TemplateVariable[];
13
+ }
14
+ /** Every built-in template with its menu label, in the order the menu lists them. */
15
+ export declare const DOCUMENT_TEMPLATES: ReadonlyArray<{
16
+ id: DocumentTemplateId;
17
+ label: EditorLabelKey;
18
+ }>;
19
+ /** Label of a built-in template variable in the editor's language, or `undefined` for other names. */
20
+ export declare const templateVariableLabel: (name: string, locale: EditorLocaleCode) => string | undefined;
21
+ /** A built-in document template in the editor's language, with the variables it uses. */
22
+ export declare const getDocumentTemplate: (id: DocumentTemplateId, locale?: EditorLocaleCode) => DocumentTemplate;