nuvra 0.5.0 → 0.7.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,10 +1,11 @@
1
+ import type { Collaborator, SelectionOffsets } from '../core/collaboration';
1
2
  import { type DocumentComment } from '../core/comments';
2
3
  import { DocumentEngine } from '../core/engine/engine';
3
4
  import { type EditorLocaleInput } from '../core/labels';
4
5
  import { type DocumentViewMode, type PageSettings } from '../core/page';
5
6
  import type { SlashCommand } from '../core/slash-commands';
6
7
  import type { TemplateVariable } from '../core/templates';
7
- import type { DocumentImageUploadHandler } from '../core/types';
8
+ import type { DocumentImageUploadHandler, ToolbarTool } from '../core/types';
8
9
  import { type EditorUiState } from '../core/ui-state';
9
10
  import '../styles/document-content.css';
10
11
  import '../styles/editor-ui.css';
@@ -15,6 +16,8 @@ interface Props {
15
16
  autofocus?: boolean;
16
17
  /** Gray space around the page or web sheet that separates the document from the editor frame. */
17
18
  canvasPadding?: CssSize;
19
+ /** Other people editing the document; their carets and selections are drawn over it. */
20
+ collaborators?: readonly Collaborator[];
18
21
  /** Name written as the author of new comments, replies and tracked changes. */
19
22
  author?: string;
20
23
  /** View shown first; form fields use the lighter web view. */
@@ -41,6 +44,11 @@ interface Props {
41
44
  ruler?: boolean;
42
45
  /** Used as the print title and the exported file name. */
43
46
  title?: string;
47
+ /**
48
+ * Toolbar tools to show, such as `['history', 'marks', 'lists', 'link']`; every tool without a list. Keyboard
49
+ * shortcuts, the `/` menu and the right-click menu are not affected.
50
+ */
51
+ tools?: readonly ToolbarTool[];
44
52
  /** Uploads an inserted image and resolves with its URL; without it images are embedded as data URLs. */
45
53
  uploadImage?: DocumentImageUploadHandler;
46
54
  /** Template variables the user can insert; typing `{{name}}` of one of them inserts it as well. */
@@ -76,6 +84,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
76
84
  exportHtml: () => Promise<void>;
77
85
  /** Downloads the document as a Word-compatible file. */
78
86
  exportWord: () => Promise<void>;
87
+ /** Downloads the document as a PDF drawn from its pages. */
88
+ exportPdf: () => Promise<void>;
79
89
  /** Moves keyboard focus into the document. */
80
90
  focus: () => void | undefined;
81
91
  /** Returns the document HTML, including edits not yet written to the model. */
@@ -94,6 +104,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
94
104
  "update:page": (value: PageSettings) => any;
95
105
  uploadError: (error: unknown) => any;
96
106
  importError: (error: unknown) => any;
107
+ exportError: (error: unknown) => any;
108
+ selectionChange: (selection: SelectionOffsets | null) => any;
97
109
  "update:modelValue": (value: string) => any;
98
110
  "update:trackChanges": (value: boolean) => any;
99
111
  "update:comments": (value: DocumentComment[] | undefined) => any;
@@ -103,6 +115,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
103
115
  "onUpdate:page"?: ((value: PageSettings) => any) | undefined;
104
116
  onUploadError?: ((error: unknown) => any) | undefined;
105
117
  onImportError?: ((error: unknown) => any) | undefined;
118
+ onExportError?: ((error: unknown) => any) | undefined;
119
+ onSelectionChange?: ((selection: SelectionOffsets | null) => any) | undefined;
106
120
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
107
121
  "onUpdate:trackChanges"?: ((value: boolean) => any) | undefined;
108
122
  "onUpdate:comments"?: ((value: DocumentComment[] | undefined) => any) | undefined;
@@ -111,12 +125,14 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
111
125
  height: CssSize;
112
126
  locale: EditorLocaleInput;
113
127
  ruler: boolean;
128
+ variables: readonly TemplateVariable[];
114
129
  placeholder: string;
115
130
  disabled: boolean;
116
131
  minHeight: CssSize;
132
+ collaborators: readonly Collaborator[];
117
133
  maxHeight: CssSize;
118
134
  maxLength: number;
119
- variables: readonly TemplateVariable[];
135
+ tools: readonly ToolbarTool[];
120
136
  author: string;
121
137
  autofocus: boolean;
122
138
  canvasPadding: CssSize;
@@ -2,6 +2,7 @@ import type { ParagraphIndents } from '../core/engine/blocks';
2
2
  import type { DocumentEngine } from '../core/engine/engine';
3
3
  import { type SheetFootnote } from '../core/footnotes';
4
4
  import { type DocumentViewMode, type PageMargins, type PageMetrics, type PageSettings } from '../core/page';
5
+ import { type SheetGeometry } from '../core/pagination';
5
6
  interface Props {
6
7
  /** Grow with the content between the editor's min and max height instead of filling a fixed height. */
7
8
  autoHeight: boolean;
@@ -21,6 +22,8 @@ interface Props {
21
22
  metrics: PageMetrics;
22
23
  /** Number of sheets drawn behind the content in page view. */
23
24
  pageCount: number;
25
+ /** Position, size and orientation of every sheet, as laid out by pagination; empty until the first layout. */
26
+ sheets: readonly SheetGeometry[];
24
27
  /** Whether the ruler is drawn above the sheet; it is only ever shown in the page view. */
25
28
  rulerVisible: boolean;
26
29
  /** Paginated sheets or a single web sheet. */
@@ -0,0 +1,17 @@
1
+ import { type Collaborator } from '../core/collaboration';
2
+ import type { DocumentEngine } from '../core/engine/engine';
3
+ interface Props {
4
+ /** Engine that measures positions in the document. */
5
+ engine: DocumentEngine;
6
+ /** People whose carets are drawn. */
7
+ collaborators: readonly Collaborator[];
8
+ /** Element the marks are positioned in; it must be positioned itself. */
9
+ container: HTMLElement;
10
+ /** Scrolling canvas; marks outside it are hidden. */
11
+ scrollTarget: HTMLElement;
12
+ /** Changes whenever the layout may move text (zoom, view mode, page setup), so the marks are measured again. */
13
+ layoutKey: string;
14
+ }
15
+ 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>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
@@ -1,16 +1,36 @@
1
- import type { OutlineHeading } from '../core/outline';
1
+ import type { OutlineHeading, OutlineView } from '../core/outline';
2
+ import type { PageMetrics } from '../core/page';
3
+ import type { SheetGeometry } from '../core/pagination';
2
4
  interface Props {
3
5
  /** Headings of the document with the page each starts on, `null` outside the page view. */
4
6
  headings: ReadonlyArray<OutlineHeading & {
5
7
  page: number | null;
6
8
  }>;
9
+ /** Clean HTML of every sheet, shown as page thumbnails; empty outside the page view. */
10
+ pages: readonly string[];
11
+ /** Page geometry the thumbnails are scaled from. */
12
+ metrics: PageMetrics;
13
+ /** Size of every sheet; a sheet turned by a section break gets a turned thumbnail. */
14
+ sheets: readonly SheetGeometry[];
15
+ /** Number printed on the first sheet. */
16
+ firstPageNumber: number;
7
17
  }
8
- declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ type __VLS_Props = Props;
19
+ type __VLS_ModelProps = {
20
+ /** Which list is shown; the editor reads it to lay out thumbnails only while they are visible. */
21
+ 'view'?: OutlineView;
22
+ };
23
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
24
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
25
  select: (heading: HTMLElement) => any;
10
26
  close: () => any;
11
- }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
27
+ selectPage: (index: number) => any;
28
+ "update:view": (value: OutlineView) => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
12
30
  onSelect?: ((heading: HTMLElement) => any) | undefined;
13
31
  onClose?: (() => any) | undefined;
32
+ onSelectPage?: ((index: number) => any) | undefined;
33
+ "onUpdate:view"?: ((value: OutlineView) => any) | undefined;
14
34
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
35
  declare const _default: typeof __VLS_export;
16
36
  export default _default;
@@ -1,7 +1,7 @@
1
1
  import type { DocumentEngine } from '../core/engine/engine';
2
2
  import { type PageSettings } from '../core/page';
3
3
  import type { TemplateVariable } from '../core/templates';
4
- import type { DocumentMenuAction } from '../core/types';
4
+ import { type DocumentMenuAction, type ToolbarTool } from '../core/types';
5
5
  import { type EditorUiState } from '../core/ui-state';
6
6
  interface Props {
7
7
  /** Read-only document: every editing control is disabled. */
@@ -36,10 +36,12 @@ interface Props {
36
36
  uploading: boolean;
37
37
  /** Template variables offered by the variable menu; the menu is hidden without any. */
38
38
  variables: ReadonlyArray<TemplateVariable>;
39
+ /** Tools to show; every tool without a list. */
40
+ tools: readonly ToolbarTool[] | undefined;
39
41
  }
40
- declare var __VLS_604: {};
42
+ declare var __VLS_626: {};
41
43
  type __VLS_Slots = {} & {
42
- default?: (props: typeof __VLS_604) => any;
44
+ default?: (props: typeof __VLS_626) => any;
43
45
  };
44
46
  declare const __VLS_base: import("vue").DefineComponent<Props, {
45
47
  /** Opens the link popover. */
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Hooks for editing a document together. The editor reports where the caret is and draws the carets and selections
3
+ * of other people; sending the document and the selections between them (WebSocket, WebRTC, a CRDT such as Yjs) is
4
+ * left to the application.
5
+ */
6
+ /** A selection as character positions through the document; equal positions are a caret. */
7
+ export interface SelectionOffsets {
8
+ /** Where selecting started. */
9
+ anchor: number;
10
+ /** Where the caret is. */
11
+ focus: number;
12
+ }
13
+ /** Someone else edits the same document. */
14
+ export interface Collaborator {
15
+ /** Stable id of the person or connection. */
16
+ id: string;
17
+ /** Name shown next to the caret. */
18
+ name: string;
19
+ /** CSS color of the caret and the selection; one is picked from the id when it is left out. */
20
+ color?: string;
21
+ /** Where the person's caret or selection is, or `null` while they are not in the document. */
22
+ selection: SelectionOffsets | null;
23
+ }
24
+ /** The color of a collaborator: their own, or a stable one derived from the id. */
25
+ export declare const collaboratorColor: (collaborator: Pick<Collaborator, "id" | "color">) => string;
@@ -8,7 +8,7 @@ import { type PageSettings } from '../page';
8
8
  export interface DocxImport {
9
9
  /** Document content as HTML. */
10
10
  html: string;
11
- /** Page setup of the document's last section. */
11
+ /** Page setup of the document's first section; later sections are section breaks in the HTML. */
12
12
  page: PageSettings;
13
13
  }
14
14
  /**
@@ -15,7 +15,7 @@ export declare const imageFiles: (content: TransferContent) => File[];
15
15
  export declare const singleUrl: (content: TransferContent) => string | null;
16
16
  /** Converts plain text into paragraphs, one per line; a final line break does not add an empty paragraph. */
17
17
  export declare const textToFragment: (text: string) => DocumentFragment;
18
- /** Converts a payload into editor blocks, preferring sanitised HTML over plain text; `null` when it has neither. */
18
+ /** Converts a payload into editor blocks, preferring sanitized HTML over plain text; `null` when it has neither. */
19
19
  export declare const transferToFragment: (content: TransferContent) => DocumentFragment | null;
20
20
  /** Clean HTML and plain text of a selection, as put on the clipboard by copy, cut and drag. */
21
21
  export declare const selectionClipboardData: (root: HTMLElement, range: Range) => {
@@ -13,8 +13,15 @@ export declare const FOOTNOTE_ATTRIBUTE = "data-footnote";
13
13
  export declare const FOOTNOTE_SELECTOR = "sup[data-footnote]";
14
14
  /** Selector for every inline atom: elements inside a line that behave as one character and hold no editable text. */
15
15
  export declare const INLINE_ATOM_SELECTOR = "span[data-variable], sup[data-footnote]";
16
- /** Selector for blocks without editable text inside: rules, images and page breaks. */
17
- export declare const ATOM_SELECTOR = "hr, img, div[data-type=\"page-break\"]";
16
+ /** Selector for blocks without editable text inside: rules, images, page breaks and section breaks. */
17
+ export declare const ATOM_SELECTOR = "hr, img, div[data-type=\"page-break\"], div[data-type=\"section-break\"]";
18
+ /** Whether a `<div>` is one of the break blocks the document model keeps: a page break or a section break. */
19
+ export declare const isBreakBlock: (node: Node | null | undefined) => boolean;
20
+ /**
21
+ * Creates a section break: the sheets after it are turned to `orientation`. It also starts a new sheet, so it is drawn
22
+ * and printed like a page break.
23
+ */
24
+ export declare const createSectionBreak: (orientation: "portrait" | "landscape") => HTMLDivElement;
18
25
  /** Selector for blocks that hold editable inline text. */
19
26
  export declare const TEXT_BLOCK_SELECTOR = "p, h1, h2, h3, h4, h5, h6, pre";
20
27
  /** Marks the extra `<br>` that keeps an empty or break-terminated line visible; it is never serialised. */
@@ -6,6 +6,7 @@ import { EditorHistory } from './history';
6
6
  import { type ListKind } from './lists';
7
7
  import { type MarkName, type StyleName, type TextCase } from './marks';
8
8
  import { SearchController, type SearchState } from './search';
9
+ import { type TextBookmark } from './selection';
9
10
  import { type TableCell } from './tables';
10
11
  /** A tracked insertion or deletion; the parts of one edit are joined. */
11
12
  export interface TrackedChange {
@@ -162,10 +163,23 @@ export declare class DocumentEngine {
162
163
  * @param options.addToHistory Record the replacement as an undo step instead of clearing the history.
163
164
  * @param options.emitUpdate Emit `update` so the host saves the new content.
164
165
  */
165
- setContent(html: string, { addToHistory, emitUpdate }?: {
166
+ setContent(html: string, { addToHistory, emitUpdate, keepSelection }?: {
166
167
  addToHistory?: boolean | undefined;
167
168
  emitUpdate?: boolean | undefined;
169
+ keepSelection?: boolean | undefined;
168
170
  }): void;
171
+ /**
172
+ * The selection as character positions through the document: `anchor` where selecting started, `focus` where the
173
+ * caret is. Positions survive changes to the markup, so they can be sent to other people editing the document.
174
+ */
175
+ getSelectionOffsets(): TextBookmark | null;
176
+ /**
177
+ * Viewport rectangles of the text between two character positions, for drawing someone else's selection; a
178
+ * collapsed position gives the rectangle of its caret line with no width.
179
+ */
180
+ getOffsetRects(offsets: TextBookmark): DOMRect[];
181
+ /** Number of character positions in the document, the largest offset a selection can have. */
182
+ private characterPositions;
169
183
  /** Switches between editing and read-only mode. */
170
184
  setEditable(editable: boolean): void;
171
185
  /** Word and character counts of the document text. */
@@ -395,6 +409,8 @@ export declare class DocumentEngine {
395
409
  private insertBlock;
396
410
  /** Inserts a horizontal rule. */
397
411
  insertHorizontalRule(): void;
412
+ /** Inserts a section break: the sheets after it are turned to `orientation`, for example for a wide table. */
413
+ insertSectionBreak(orientation: 'portrait' | 'landscape'): void;
398
414
  /** Inserts a manual page break. */
399
415
  insertPageBreak(): void;
400
416
  /**
@@ -2,8 +2,16 @@
2
2
  export declare const VARIABLE_NAME: RegExp;
3
3
  /** Attribute holding the label a variable chip shows in the editor; editor-only. */
4
4
  export declare const VARIABLE_LABEL_ATTRIBUTE = "data-label";
5
+ /** Attribute pagination writes on blocks of a section turned against the document's orientation; editor-only. */
6
+ export declare const ROTATED_ATTRIBUTE = "data-doc-rotated";
5
7
  /** Attribute pagination writes on blocks it moved to the next sheet; editor-only. */
6
8
  export declare const GAP_ATTRIBUTE = "data-doc-gap";
9
+ /** Attribute pagination writes on table rows it moved down to the next sheet, with the shift in pixels; editor-only. */
10
+ export declare const ROW_SHIFT_ATTRIBUTE = "data-doc-row-shift";
11
+ /** Attribute pagination writes on tables split over sheets, with the space their moved rows add; editor-only. */
12
+ export declare const TABLE_SHIFT_ATTRIBUTE = "data-doc-table-shift";
13
+ /** Attribute pagination sets on the editable root while the document is laid out on sheets; editor-only. */
14
+ export declare const PAGED_ATTRIBUTE = "data-doc-paged";
7
15
  /** Class marking table cells in a drag selection; editor-only. */
8
16
  export declare const SELECTED_CELL_CLASS = "doc-cell-selected";
9
17
  /** Attribute holding the space a paragraph keeps before it, in points. */
@@ -9,6 +9,8 @@ interface DocumentSnapshot {
9
9
  * with real page numbers and breaks the pages exactly where the editor shows them.
10
10
  */
11
11
  pages?: string[];
12
+ /** For every sheet of `pages`, whether a section break turned it against the document's orientation. */
13
+ rotated?: boolean[];
12
14
  /** Footnotes of every sheet of `pages`; without pages, the notes of all of them are printed after the document. */
13
15
  footnotes?: SheetFootnote[][];
14
16
  /** Document title, used for the print title and file names. */
@@ -16,6 +18,11 @@ interface DocumentSnapshot {
16
18
  /** Page size, orientation, margins and the running texts. */
17
19
  page: PageSettings;
18
20
  }
21
+ /** Paper width and height in millimetres, in the chosen orientation. */
22
+ export declare const paperSize: ({ size, orientation }: PageSettings) => {
23
+ width: number;
24
+ height: number;
25
+ };
19
26
  /** Turns a document title into a safe file name without extension. */
20
27
  export declare const toFileName: (title: string) => string;
21
28
  /**
@@ -24,7 +31,7 @@ export declare const toFileName: (title: string) => string;
24
31
  * the pages break where the editor shows them; without them the document flows and the browser repeats one fixed
25
32
  * header and footer on every page.
26
33
  */
27
- export declare const buildPrintableHtml: ({ html, pages, footnotes, title, page }: DocumentSnapshot) => string;
34
+ export declare const buildPrintableHtml: ({ html, pages, rotated, footnotes, title, page }: DocumentSnapshot) => string;
28
35
  /** Offers text or binary content as a file download. */
29
36
  export declare const downloadFile: (content: string | Blob, fileName: string, type: string) => void;
30
37
  /** Prints through a detached iframe so the application chrome never ends up on paper. Waits for images first. */
@@ -59,6 +59,7 @@ export declare const uz: {
59
59
  readonly 'editor.enterFullscreen': "To‘liq ekran";
60
60
  readonly 'editor.exitFullscreen': "To‘liq ekrandan chiqish";
61
61
  readonly 'editor.exportHtml': "HTML sifatida yuklab olish";
62
+ readonly 'editor.exportPdf': "PDF sifatida yuklab olish";
62
63
  readonly 'editor.exportWord': "Word (.docx) sifatida yuklab olish";
63
64
  readonly 'editor.fitWidth': "Kenglikka moslash";
64
65
  readonly 'editor.fontFamily': "Shrift";
@@ -112,6 +113,10 @@ export declare const uz: {
112
113
  readonly 'editor.numbering.legal': "Ko‘p darajali raqamlash (1.1, 1.2)";
113
114
  readonly 'editor.outline': "Navigatsiya paneli";
114
115
  readonly 'editor.outline.empty': "Hujjatda sarlavhalar yo‘q. Sarlavha uslubini qo‘llang, ular shu yerda ko‘rinadi.";
116
+ readonly 'editor.outline.headings': "Sarlavhalar";
117
+ readonly 'editor.outline.noPages': "Sahifalar faqat sahifa ko‘rinishida chiqadi.";
118
+ readonly 'editor.outline.page': "{page}-sahifa";
119
+ readonly 'editor.outline.pages': "Sahifalar";
115
120
  readonly 'editor.openLink': "Havolani ochish";
116
121
  readonly 'editor.or': "yoki havola orqali";
117
122
  readonly 'editor.orderedList': "Raqamli ro‘yxat";
@@ -147,6 +152,7 @@ export declare const uz: {
147
152
  readonly 'editor.replace.one': "Almashtirish";
148
153
  readonly 'editor.replace.placeholder': "Almashtirish";
149
154
  readonly 'editor.replace.toggle': "Almashtirishni ko‘rsatish";
155
+ readonly 'editor.review': "Taqriz: izohlar va o‘zgarishlar";
150
156
  readonly 'editor.ruler': "Chizg‘ich";
151
157
  readonly 'editor.ruler.firstLine': "Birinchi qator chekinishi";
152
158
  readonly 'editor.ruler.indentLeft': "Chap chekinish";
@@ -160,6 +166,8 @@ export declare const uz: {
160
166
  readonly 'editor.search.title': "Qidirish va almashtirish";
161
167
  readonly 'editor.search.wholeWord': "Butun so‘z";
162
168
  readonly 'editor.selectAll': "Barchasini tanlash";
169
+ readonly 'editor.sectionBreak.landscape': "Bo‘lim uzilishi: albom sahifalar";
170
+ readonly 'editor.sectionBreak.portrait': "Bo‘lim uzilishi: kitob sahifalar";
163
171
  readonly 'editor.signature': "Imzo bloki";
164
172
  readonly 'editor.signature.agreed': "KELISHILDI grifi";
165
173
  readonly 'editor.signature.approval': "TASDIQLAYMAN grifi";
@@ -12,6 +12,8 @@ export interface OutlineHeading {
12
12
  /** The heading element in the editable document. */
13
13
  element: HTMLElement;
14
14
  }
15
+ /** What the navigation panel lists: the headings, or thumbnails of the pages. */
16
+ export type OutlineView = 'headings' | 'pages';
15
17
  /** A line of the table of contents. */
16
18
  export interface TableOfContentsEntry {
17
19
  /** Heading level, 1 to 6; deeper levels are indented. */
@@ -1,5 +1,18 @@
1
1
  import { type SheetFootnote } from './footnotes';
2
- import type { PageMetrics } from './page';
2
+ import type { PageMetrics, PageOrientation } from './page';
3
+ /** Where a sheet is drawn and which way it is turned. */
4
+ export interface SheetGeometry {
5
+ /** Distance of the sheet from the top of the first sheet, in pixels. */
6
+ top: number;
7
+ /** Sheet width in pixels. */
8
+ width: number;
9
+ /** Sheet height in pixels. */
10
+ height: number;
11
+ /** Orientation of the sheet. */
12
+ orientation: PageOrientation;
13
+ /** Whether the sheet is turned against the document's own orientation, by a section break. */
14
+ rotated: boolean;
15
+ }
3
16
  /** Handle returned by {@link createPagination}. */
4
17
  export interface PaginationController {
5
18
  /** Sets the page geometry and re-runs the layout; pass `null` to switch pagination off (web view). */
@@ -15,15 +28,21 @@ interface PaginationOptions {
15
28
  onPageCount: (count: number) => void;
16
29
  /** Receives the footnotes of every sheet whenever they change; the web view is one sheet holding all of them. */
17
30
  onFootnotes?: (sheets: SheetFootnote[][]) => void;
31
+ /** Receives the position, size and orientation of every sheet whenever they change; empty in the web view. */
32
+ onSheets?: (sheets: SheetGeometry[]) => void;
18
33
  /** Whether an IME composition is in progress, during which blocks must not move. */
19
34
  isComposing: () => boolean;
20
35
  }
36
+ /** Sheets of a document without section breaks, all alike. */
37
+ export declare const uniformSheets: (metrics: PageMetrics, count: number) => SheetGeometry[];
38
+ /** Index of the sheet a vertical position falls on, counted from the top of the first sheet. */
39
+ export declare const sheetIndexAt: (sheets: readonly SheetGeometry[], offset: number) => number;
21
40
  /**
22
41
  * Splits the laid-out document into the clean HTML of every sheet, for printing and export. Pagination has already
23
42
  * moved every block onto its page, so a block belongs to the page its top falls on; blocks taller than a page stay
24
43
  * whole, exactly as they are shown on screen. Footnote references keep their document-wide numbers.
25
44
  */
26
- export declare const splitIntoPages: (root: HTMLElement, metrics: PageMetrics, pageCount: number) => string[];
45
+ export declare const splitIntoPages: (root: HTMLElement, metrics: PageMetrics, pageCount: number, geometry?: readonly SheetGeometry[]) => string[];
27
46
  /**
28
47
  * Keeps the document laid out on sheets. Layout passes are batched to one per animation frame and re-run when the
29
48
  * document resizes, images or fonts load, or the host schedules one after an edit.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * PDF download without the print dialog and without dependencies. Every sheet of the printable document is drawn into
3
+ * a canvas through an SVG `foreignObject`, and the pictures are written into a PDF, one per page. The PDF looks like
4
+ * the printout, but its text cannot be selected or searched.
5
+ */
6
+ /** A rendered page: a JPEG picture of the sheet and the paper size it is printed on. */
7
+ export interface PdfPage {
8
+ /** JPEG data of the page picture. */
9
+ jpeg: Uint8Array;
10
+ /** Picture width in pixels. */
11
+ width: number;
12
+ /** Picture height in pixels. */
13
+ height: number;
14
+ /** Paper width in PDF points (1/72 inch). */
15
+ widthPt: number;
16
+ /** Paper height in PDF points. */
17
+ heightPt: number;
18
+ }
19
+ /** Options of {@link renderPdf}. */
20
+ export interface PdfOptions {
21
+ /** Pixels per CSS pixel of the page pictures; higher is sharper and larger. Defaults to 2. */
22
+ scale?: number;
23
+ /** JPEG quality between 0 and 1. Defaults to 0.92. */
24
+ quality?: number;
25
+ }
26
+ /** MIME type of PDF files. */
27
+ export declare const PDF_MIME = "application/pdf";
28
+ /**
29
+ * Writes JPEG pictures into a PDF document, one picture filling each page.
30
+ *
31
+ * @returns the PDF file content.
32
+ */
33
+ export declare const buildPdf: (pages: readonly PdfPage[]) => Uint8Array;
34
+ /**
35
+ * Turns the printable HTML of a paginated document (one `section.doc-sheet` per page) into a PDF.
36
+ *
37
+ * @param printableHtml Standalone HTML as built for printing from the page view.
38
+ * @param paper Paper width and height in millimetres, in the chosen orientation.
39
+ */
40
+ export declare const renderPdf: (printableHtml: string, paper: {
41
+ width: number;
42
+ height: number;
43
+ }, options?: PdfOptions) => Promise<Blob>;
@@ -1,3 +1,10 @@
1
1
  /** Uploads an image and resolves with its public URL. Without a handler, images are embedded as data URLs. */
2
2
  export type DocumentImageUploadHandler = (file: File) => Promise<string>;
3
- export type DocumentMenuAction = 'source' | 'print' | 'exportHtml' | 'exportWord' | 'importWord' | 'formattingMarks' | 'ruler' | 'outline' | 'tableOfContents' | 'comments' | 'addComment' | 'footnote' | 'trackChanges' | 'changes' | 'fullscreen';
3
+ export type DocumentMenuAction = 'source' | 'print' | 'exportHtml' | 'exportWord' | 'exportPdf' | 'importWord' | 'formattingMarks' | 'ruler' | 'outline' | 'tableOfContents' | 'comments' | 'addComment' | 'footnote' | 'trackChanges' | 'changes' | 'fullscreen';
4
+ /**
5
+ * Tools of the editor toolbar, in the order they appear. Pass a list of them as the `tools` prop to show only those;
6
+ * keyboard shortcuts, the `/` menu and the right-click menu keep working either way.
7
+ */
8
+ export declare const TOOLBAR_TOOLS: readonly ["history", "formatPainter", "blockStyle", "fontFamily", "fontSize", "marks", "textCase", "color", "highlight", "align", "lineHeight", "direction", "lists", "indent", "link", "image", "table", "specialCharacters", "variables", "signature", "insert", "review", "search", "templates", "headerFooter", "pageSetup", "more"];
9
+ /** A tool of the editor toolbar; see {@link TOOLBAR_TOOLS}. */
10
+ export type ToolbarTool = (typeof TOOLBAR_TOOLS)[number];
@@ -1,6 +1,6 @@
1
1
  import type { EditorLocaleInput } from './core/labels';
2
2
  import type { TemplateVariable } from './core/templates';
3
- import type { DocumentImageUploadHandler } from './core/types';
3
+ import type { DocumentImageUploadHandler, ToolbarTool } from './core/types';
4
4
  interface Props {
5
5
  /** Places the caret at the end of the content once the editor is ready. */
6
6
  autofocus?: boolean;
@@ -20,6 +20,8 @@ interface Props {
20
20
  minHeight?: number | string;
21
21
  /** Text shown while the field is empty. */
22
22
  placeholder?: string;
23
+ /** Toolbar tools to show; every tool without a list. */
24
+ tools?: readonly ToolbarTool[];
23
25
  /** Uploads an image and resolves with its URL; without it images are embedded as data URLs. */
24
26
  uploadImage?: DocumentImageUploadHandler;
25
27
  /** Template variables the user can insert; typing `{{name}}` of one of them inserts it as well. */
@@ -43,12 +45,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
43
45
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
44
46
  }>, {
45
47
  locale: EditorLocaleInput;
48
+ variables: readonly TemplateVariable[];
46
49
  placeholder: string;
47
50
  disabled: boolean;
48
51
  minHeight: number | string;
49
52
  maxHeight: number | string;
50
53
  maxLength: number;
51
- variables: readonly TemplateVariable[];
54
+ tools: readonly ToolbarTool[];
52
55
  autofocus: boolean;
53
56
  canvasPadding: number | string;
54
57
  maxImageSizeMb: number;
@@ -33,18 +33,20 @@ var c = ".doc-content{color:#1f2328;white-space:pre-wrap;overflow-wrap:break-wor
33
33
  let { width: i, height: a } = y(e), s = t(i * m, a * m, r.text, r.diagonal), c = r.diagonal ? " transform: rotate(-35deg);" : "";
34
34
  return `
35
35
  .doc-watermark { position: ${n ? "fixed" : "absolute"}; inset: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; color: ${r.color}; font: 700 ${s}px/1 'Times New Roman', Times, serif; letter-spacing: 0.06em; opacity: ${h}; text-transform: uppercase; white-space: nowrap; pointer-events: none;${c} }`;
36
- }, E = (t, n, r, a = []) => t.map((o, c) => {
37
- let l = {
38
- page: e(n, c + 1),
36
+ }, E = (t, n, r, a = [], o = []) => t.map((c, l) => {
37
+ let u = {
38
+ page: e(n, l + 1),
39
39
  pages: t.length,
40
40
  title: r
41
- }, u = i(n, c + 1), d = u ? C(n.header, "header", l) : "", f = u ? C(n.footer, "footer", l) : "";
42
- return `<section class="doc-sheet">${w(n.watermark)}${d}<article class="doc-content">${o}</article>${a[c]?.length ? `<div class="doc-sheet__notes">${s(a[c] ?? [])}</div>` : ""}${f}</section>`;
41
+ }, d = i(n, l + 1), f = d ? C(n.header, "header", u) : "", p = d ? C(n.footer, "footer", u) : "", m = w(n.watermark), h = a[l]?.length ? `<div class="doc-sheet__notes">${s(a[l] ?? [])}</div>` : "";
42
+ return `<section class="${o[l] ? "doc-sheet is-rotated" : "doc-sheet"}">${m}${f}<article class="doc-content">${c}</article>${h}${p}</section>`;
43
43
  }).join(""), D = (e) => {
44
44
  let { width: t, height: n } = y(e), { margins: r } = e;
45
45
  return `@page { size: ${t}mm ${n}mm; margin: 0; }
46
46
  .doc-sheet { position: relative; box-sizing: border-box; width: ${t}mm; min-height: ${n}mm; padding: ${r.top}mm ${r.right}mm ${r.bottom}mm ${r.left}mm; overflow: hidden; background: #fff; break-after: page; }
47
47
  .doc-sheet:last-child { break-after: auto; }
48
+ @page rotated { size: ${n}mm ${t}mm; margin: 0; }
49
+ .doc-sheet.is-rotated { width: ${n}mm; min-height: ${t}mm; page: rotated; }
48
50
  .doc-running { position: absolute; right: ${r.right}mm; left: ${r.left}mm; }
49
51
  .doc-sheet__notes { position: absolute; right: ${r.right}mm; bottom: ${r.bottom}mm; left: ${r.left}mm; }
50
52
  .doc-running--header { top: ${x(r.top)}mm; }
@@ -55,20 +57,20 @@ var c = ".doc-content{color:#1f2328;white-space:pre-wrap;overflow-wrap:break-wor
55
57
  .doc-running { position: fixed; right: 0; left: 0; }
56
58
  .doc-running--header { top: -${x(t.top)}mm; }
57
59
  .doc-running--footer { bottom: -${x(t.bottom)}mm; }${S}${T(e, !0)}`;
58
- }, k = (e) => e.replace(u, " ").trim() || d, A = ({ html: e, pages: t, footnotes: n, title: r, page: i }) => {
59
- let a = t !== void 0 && t.length > 0, o = {
60
+ }, k = (e) => e.replace(u, " ").trim() || d, A = ({ html: e, pages: t, rotated: n, footnotes: r, title: i, page: a }) => {
61
+ let o = t !== void 0 && t.length > 0, l = {
60
62
  page: 1,
61
63
  pages: 1,
62
- title: r
63
- }, l = `${w(i.watermark)}${C(i.header, "header", o)}${C(i.footer, "footer", o)}<article class="doc-content">${e}</article>${s(n?.flat() ?? [])}`;
64
+ title: i
65
+ }, u = `${w(a.watermark)}${C(a.header, "header", l)}${C(a.footer, "footer", l)}<article class="doc-content">${e}</article>${s(r?.flat() ?? [])}`;
64
66
  return `<!doctype html>
65
67
  <html lang="uz">
66
68
  <head>
67
69
  <meta charset="utf-8">
68
- <title>${v(r)}</title>
69
- <style>${a ? D(i) : O(i)} html, body { margin: 0; background: #fff; } ${c}</style>
70
+ <title>${v(i)}</title>
71
+ <style>${o ? D(a) : O(a)} html, body { margin: 0; background: #fff; } ${c}</style>
70
72
  </head>
71
- <body>${a && t ? E(t, i, r, n) : l}</body>
73
+ <body>${o && t ? E(t, a, i, r, n) : u}</body>
72
74
  </html>`;
73
75
  }, j = (e, t, n) => {
74
76
  let r = URL.createObjectURL(e instanceof Blob ? e : new Blob([e], { type: n })), i = document.createElement("a");
@@ -89,6 +91,6 @@ var c = ".doc-content{color:#1f2328;white-space:pre-wrap;overflow-wrap:break-wor
89
91
  }, t.srcdoc = e, document.body.appendChild(t);
90
92
  };
91
93
  //#endregion
92
- export { A as buildPrintableHtml, j as downloadFile, M as printHtml, k as toFileName };
94
+ export { A as buildPrintableHtml, j as downloadFile, y as paperSize, M as printHtml, k as toFileName };
93
95
 
94
- //# sourceMappingURL=export-DhHI3ZrQ.js.map
96
+ //# sourceMappingURL=export-B06RXLqn.js.map