nuvra 0.1.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.
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/components/document-editor.vue.d.ts +82 -0
- package/dist/components/editor-bubble-menus.vue.d.ts +14 -0
- package/dist/components/editor-canvas.vue.d.ts +30 -0
- package/dist/components/editor-color-picker.vue.d.ts +15 -0
- package/dist/components/editor-find-bar.vue.d.ts +24 -0
- package/dist/components/editor-object-overlay.vue.d.ts +10 -0
- package/dist/components/editor-page-setup.vue.d.ts +12 -0
- package/dist/components/editor-status-bar.vue.d.ts +36 -0
- package/dist/components/editor-table-picker.vue.d.ts +16 -0
- package/dist/components/editor-toolbar.vue.d.ts +38 -0
- package/dist/core/engine/blocks.d.ts +37 -0
- package/dist/core/engine/clipboard.d.ts +23 -0
- package/dist/core/engine/dom.d.ts +64 -0
- package/dist/core/engine/editing.d.ts +44 -0
- package/dist/core/engine/engine.d.ts +319 -0
- package/dist/core/engine/history.d.ts +43 -0
- package/dist/core/engine/input-rules.d.ts +17 -0
- package/dist/core/engine/keymap.d.ts +7 -0
- package/dist/core/engine/lists.d.ts +29 -0
- package/dist/core/engine/marks.d.ts +50 -0
- package/dist/core/engine/schema.d.ts +37 -0
- package/dist/core/engine/search.d.ts +65 -0
- package/dist/core/engine/selection.d.ts +30 -0
- package/dist/core/engine/tables.d.ts +59 -0
- package/dist/core/export.d.ts +21 -0
- package/dist/core/labels.d.ts +150 -0
- package/dist/core/page.d.ts +109 -0
- package/dist/core/pagination.d.ts +23 -0
- package/dist/core/types.d.ts +3 -0
- package/dist/core/ui-state.d.ts +79 -0
- package/dist/editor.vue.d.ts +50 -0
- package/dist/export-cyOnlakM.js +59 -0
- package/dist/export-cyOnlakM.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +4900 -0
- package/dist/index.js.map +1 -0
- package/dist/page-CEEleKNI.js +93 -0
- package/dist/page-CEEleKNI.js.map +1 -0
- package/dist/style.css +2 -0
- package/package.json +72 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** A `<td>` or `<th>` element. */
|
|
2
|
+
export type TableCell = HTMLTableCellElement;
|
|
3
|
+
/** Rectangular block of grid slots, inclusive on every side. */
|
|
4
|
+
export interface CellRect {
|
|
5
|
+
/** Table the rectangle belongs to. */
|
|
6
|
+
table: HTMLTableElement;
|
|
7
|
+
/** First row index. */
|
|
8
|
+
top: number;
|
|
9
|
+
/** First column index. */
|
|
10
|
+
left: number;
|
|
11
|
+
/** Last row index. */
|
|
12
|
+
bottom: number;
|
|
13
|
+
/** Last column index. */
|
|
14
|
+
right: number;
|
|
15
|
+
}
|
|
16
|
+
/** Creates an empty table; with `withHeaderRow` the first row uses header cells. */
|
|
17
|
+
export declare const createTable: (rows: number, cols: number, withHeaderRow: boolean) => HTMLTableElement;
|
|
18
|
+
/**
|
|
19
|
+
* Inserts a row above or below the cell's row span. Cells spanning across the insertion line grow instead of
|
|
20
|
+
* getting a new cell; header columns stay header cells.
|
|
21
|
+
*/
|
|
22
|
+
export declare const addRow: (cell: TableCell, side: "before" | "after") => void;
|
|
23
|
+
/** Deletes every row the cell spans; an emptied table is removed. */
|
|
24
|
+
export declare const deleteRow: (cell: TableCell) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Inserts a column left or right of the cell's column span. Cells spanning across the insertion line grow; an
|
|
27
|
+
* existing `<colgroup>` gets a matching `<col>`.
|
|
28
|
+
*/
|
|
29
|
+
export declare const addColumn: (cell: TableCell, side: "before" | "after") => void;
|
|
30
|
+
/** Deletes every column the cell spans; an emptied table is removed. */
|
|
31
|
+
export declare const deleteColumn: (cell: TableCell) => void;
|
|
32
|
+
/** Smallest rectangle containing both cells, grown until no span crosses its edge. */
|
|
33
|
+
export declare const rectBetween: (from: TableCell, to: TableCell) => CellRect | null;
|
|
34
|
+
/** Distinct cells covering the rectangle, in grid order. */
|
|
35
|
+
export declare const cellsInRect: (rect: CellRect) => TableCell[];
|
|
36
|
+
/** Whether a cell selection covers more than one cell and can therefore be merged. */
|
|
37
|
+
export declare const canMergeRect: (rect: CellRect | null) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Merges the rectangle into its top-left cell, moving the non-empty content of the other cells into it and
|
|
40
|
+
* removing rows that end up without cells.
|
|
41
|
+
* @returns the merged cell, or `null` when there was nothing to merge.
|
|
42
|
+
*/
|
|
43
|
+
export declare const mergeCells: (rect: CellRect) => TableCell | null;
|
|
44
|
+
/** Whether the cell spans several rows or columns and can therefore be split. */
|
|
45
|
+
export declare const canSplitCell: (cell: TableCell | null) => boolean;
|
|
46
|
+
/** Splits a spanning cell back into single cells; the new cells are empty and use the same cell type. */
|
|
47
|
+
export declare const splitCell: (cell: TableCell) => void;
|
|
48
|
+
/** Turns the first row into header cells, or back into body cells when it already is a header row. */
|
|
49
|
+
export declare const toggleHeaderRow: (table: HTMLTableElement) => void;
|
|
50
|
+
/** Tab order through cells; moving past the last cell appends a row. */
|
|
51
|
+
export declare const siblingCell: (cell: TableCell, direction: 1 | -1) => TableCell | null;
|
|
52
|
+
/** Current width of a column, read without touching the markup. */
|
|
53
|
+
export declare const columnWidth: (table: HTMLTableElement, index: number) => number;
|
|
54
|
+
/** Sets a column's pixel width (clamped to the minimum) and makes the table as wide as its columns. */
|
|
55
|
+
export declare const setColumnWidth: (table: HTMLTableElement, index: number, width: number) => void;
|
|
56
|
+
/** Column whose right border is within `tolerance` of `clientX`, or null when the pointer is not near a border. */
|
|
57
|
+
export declare const columnBorderAt: (table: HTMLTableElement, cell: TableCell, clientX: number, tolerance: number) => number | null;
|
|
58
|
+
/** Replaces the highlighted cell selection inside `scope` with `cells` (an empty list clears it). */
|
|
59
|
+
export declare const markSelectedCells: (scope: HTMLElement, cells: TableCell[]) => void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type PageSettings } from './page';
|
|
2
|
+
/** Everything needed to print or export the document. */
|
|
3
|
+
interface DocumentSnapshot {
|
|
4
|
+
/** Clean document HTML. */
|
|
5
|
+
html: string;
|
|
6
|
+
/** Document title, used for the print title and file names. */
|
|
7
|
+
title: string;
|
|
8
|
+
/** Page size, orientation and margins. */
|
|
9
|
+
page: PageSettings;
|
|
10
|
+
}
|
|
11
|
+
/** Turns a document title into a safe file name without extension. */
|
|
12
|
+
export declare const toFileName: (title: string) => string;
|
|
13
|
+
/** Standalone HTML with the page size and margins encoded as `@page`, used for printing and HTML export. */
|
|
14
|
+
export declare const buildPrintableHtml: ({ html, title, page }: DocumentSnapshot) => string;
|
|
15
|
+
/** Word opens HTML saved with the Office namespaces as a regular document in print layout. */
|
|
16
|
+
export declare const buildWordHtml: ({ html, title, page }: DocumentSnapshot) => string;
|
|
17
|
+
/** Offers text content as a file download. */
|
|
18
|
+
export declare const downloadFile: (content: string, fileName: string, type: string) => void;
|
|
19
|
+
/** Prints through a detached iframe so the application chrome never ends up on paper. Waits for images first. */
|
|
20
|
+
export declare const printHtml: (documentHtml: string) => void;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/** Built-in Uzbek texts, used for every key the registered translator does not translate. */
|
|
2
|
+
declare const MESSAGES: {
|
|
3
|
+
readonly 'editor.align': "Tekislash";
|
|
4
|
+
readonly 'editor.align.center': "Markazga";
|
|
5
|
+
readonly 'editor.align.justify': "Ikki tomonga";
|
|
6
|
+
readonly 'editor.align.left': "Chapga";
|
|
7
|
+
readonly 'editor.align.right': "O‘ngga";
|
|
8
|
+
readonly 'editor.apply': "Qo‘llash";
|
|
9
|
+
readonly 'editor.bold': "Qalin";
|
|
10
|
+
readonly 'editor.bulletList': "Belgili ro‘yxat";
|
|
11
|
+
readonly 'editor.clearFormatting': "Formatni tozalash";
|
|
12
|
+
readonly 'editor.close': "Yopish";
|
|
13
|
+
readonly 'editor.codeBlock': "Kod bloki";
|
|
14
|
+
readonly 'editor.colors.automatic': "Avtomatik";
|
|
15
|
+
readonly 'editor.colors.custom': "Boshqa rang…";
|
|
16
|
+
readonly 'editor.colors.none': "Rangsiz";
|
|
17
|
+
readonly 'editor.defaultFont': "Standart shrift";
|
|
18
|
+
readonly 'editor.defaultLineHeight': "Standart";
|
|
19
|
+
readonly 'editor.defaultSize': "Standart o‘lcham";
|
|
20
|
+
readonly 'editor.delete': "O‘chirish";
|
|
21
|
+
readonly 'editor.direction.auto': "Avtomatik yo‘nalish";
|
|
22
|
+
readonly 'editor.direction.ltr': "Chapdan o‘ngga";
|
|
23
|
+
readonly 'editor.direction.rtl': "O‘ngdan chapga";
|
|
24
|
+
readonly 'editor.document': "Hujjat";
|
|
25
|
+
readonly 'editor.editLink': "Havolani tahrirlash";
|
|
26
|
+
readonly 'editor.enterFullscreen': "To‘liq ekran";
|
|
27
|
+
readonly 'editor.exitFullscreen': "To‘liq ekrandan chiqish";
|
|
28
|
+
readonly 'editor.exportHtml': "HTML sifatida yuklab olish";
|
|
29
|
+
readonly 'editor.exportWord': "Word (.doc) sifatida yuklab olish";
|
|
30
|
+
readonly 'editor.fitWidth': "Kenglikka moslash";
|
|
31
|
+
readonly 'editor.fontFamily': "Shrift";
|
|
32
|
+
readonly 'editor.fontSize': "Shrift o‘lchami";
|
|
33
|
+
readonly 'editor.heading': "Sarlavha {level}";
|
|
34
|
+
readonly 'editor.highlight': "Belgilash rangi";
|
|
35
|
+
readonly 'editor.horizontalRule': "Gorizontal chiziq";
|
|
36
|
+
readonly 'editor.image': "Rasm";
|
|
37
|
+
readonly 'editor.imageAlt': "Muqobil matn (alt)";
|
|
38
|
+
readonly 'editor.imageReadError': "Rasmni o‘qib bo‘lmadi";
|
|
39
|
+
readonly 'editor.imageSizeError': "Rasm hajmi {size} MB dan oshmasligi kerak";
|
|
40
|
+
readonly 'editor.imageTypeError': "Faqat rasm fayllarini qo‘shish mumkin";
|
|
41
|
+
readonly 'editor.imageUploadError': "Rasmni yuklab bo‘lmadi";
|
|
42
|
+
readonly 'editor.indent': "Chekinishni oshirish";
|
|
43
|
+
readonly 'editor.inlineCode': "Kod";
|
|
44
|
+
readonly 'editor.insert': "Qo‘shish";
|
|
45
|
+
readonly 'editor.insertDate': "Bugungi sana";
|
|
46
|
+
readonly 'editor.insertMore': "Boshqa elementlar";
|
|
47
|
+
readonly 'editor.italic': "Kursiv";
|
|
48
|
+
readonly 'editor.lineHeight': "Qator oralig‘i";
|
|
49
|
+
readonly 'editor.link': "Havola";
|
|
50
|
+
readonly 'editor.linkNewTab': "Yangi oynada ochish";
|
|
51
|
+
readonly 'editor.linkText': "Matn";
|
|
52
|
+
readonly 'editor.linkUrl': "Manzil (URL)";
|
|
53
|
+
readonly 'editor.more': "Yana";
|
|
54
|
+
readonly 'editor.moreFormatting': "Boshqa formatlar";
|
|
55
|
+
readonly 'editor.or': "yoki havola orqali";
|
|
56
|
+
readonly 'editor.orderedList': "Raqamli ro‘yxat";
|
|
57
|
+
readonly 'editor.outdent': "Chekinishni kamaytirish";
|
|
58
|
+
readonly 'editor.page.customMargins': "Aniq qiymatlar (mm)";
|
|
59
|
+
readonly 'editor.page.landscape': "Albom";
|
|
60
|
+
readonly 'editor.page.marginBottom': "Pastki";
|
|
61
|
+
readonly 'editor.page.marginLeft': "Chap";
|
|
62
|
+
readonly 'editor.page.marginRight': "O‘ng";
|
|
63
|
+
readonly 'editor.page.marginTop': "Yuqori";
|
|
64
|
+
readonly 'editor.page.margins': "Hoshiyalar";
|
|
65
|
+
readonly 'editor.page.margins.moderate': "O‘rtacha";
|
|
66
|
+
readonly 'editor.page.margins.narrow': "Tor";
|
|
67
|
+
readonly 'editor.page.margins.normal': "Oddiy";
|
|
68
|
+
readonly 'editor.page.margins.official': "Rasmiy hujjat";
|
|
69
|
+
readonly 'editor.page.margins.wide': "Keng";
|
|
70
|
+
readonly 'editor.page.orientation': "Yo‘nalish";
|
|
71
|
+
readonly 'editor.page.portrait': "Kitob";
|
|
72
|
+
readonly 'editor.page.setup': "Sahifa sozlamalari";
|
|
73
|
+
readonly 'editor.page.size': "Qog‘oz o‘lchami";
|
|
74
|
+
readonly 'editor.pageBreak': "Sahifa uzilishi";
|
|
75
|
+
readonly 'editor.paragraph': "Oddiy matn";
|
|
76
|
+
readonly 'editor.placeholder': "Hujjat matnini kiriting…";
|
|
77
|
+
readonly 'editor.print': "Chop etish / PDF";
|
|
78
|
+
readonly 'editor.quote': "Iqtibos";
|
|
79
|
+
readonly 'editor.redo': "Qaytarish";
|
|
80
|
+
readonly 'editor.replace.all': "Barchasini";
|
|
81
|
+
readonly 'editor.replace.one': "Almashtirish";
|
|
82
|
+
readonly 'editor.replace.placeholder': "Almashtirish";
|
|
83
|
+
readonly 'editor.replace.toggle': "Almashtirishni ko‘rsatish";
|
|
84
|
+
readonly 'editor.search.caseSensitive': "Katta-kichik harfni farqlash";
|
|
85
|
+
readonly 'editor.search.next': "Keyingisi";
|
|
86
|
+
readonly 'editor.search.placeholder': "Qidirish";
|
|
87
|
+
readonly 'editor.search.previous': "Oldingisi";
|
|
88
|
+
readonly 'editor.search.title': "Qidirish va almashtirish";
|
|
89
|
+
readonly 'editor.search.wholeWord': "Butun so‘z";
|
|
90
|
+
readonly 'editor.source': "HTML kod";
|
|
91
|
+
readonly 'editor.specialCharacters': "Maxsus belgilar";
|
|
92
|
+
readonly 'editor.status.characters': "{count} belgi";
|
|
93
|
+
readonly 'editor.status.page': "Sahifa {current} / {total}";
|
|
94
|
+
readonly 'editor.status.words': "{count} so‘z";
|
|
95
|
+
readonly 'editor.strike': "Ustidan chizilgan";
|
|
96
|
+
readonly 'editor.subscript': "Pastki indeks";
|
|
97
|
+
readonly 'editor.superscript': "Yuqori indeks";
|
|
98
|
+
readonly 'editor.table.addColumnAfter': "O‘ngga ustun qo‘shish";
|
|
99
|
+
readonly 'editor.table.addColumnBefore': "Chapga ustun qo‘shish";
|
|
100
|
+
readonly 'editor.table.addRowAfter': "Pastga qator qo‘shish";
|
|
101
|
+
readonly 'editor.table.addRowBefore': "Yuqoriga qator qo‘shish";
|
|
102
|
+
readonly 'editor.table.delete': "Jadvalni o‘chirish";
|
|
103
|
+
readonly 'editor.table.deleteColumn': "Ustunni o‘chirish";
|
|
104
|
+
readonly 'editor.table.deleteRow': "Qatorni o‘chirish";
|
|
105
|
+
readonly 'editor.table.headerRow': "Sarlavha qatori";
|
|
106
|
+
readonly 'editor.table.insert': "Jadval qo‘shish";
|
|
107
|
+
readonly 'editor.table.mergeCells': "Kataklarni birlashtirish";
|
|
108
|
+
readonly 'editor.table.pickSize': "O‘lchamni tanlang";
|
|
109
|
+
readonly 'editor.table.splitCell': "Katakni ajratish";
|
|
110
|
+
readonly 'editor.table.title': "Jadval";
|
|
111
|
+
readonly 'editor.taskList': "Vazifalar ro‘yxati";
|
|
112
|
+
readonly 'editor.textColor': "Matn rangi";
|
|
113
|
+
readonly 'editor.textDirection': "Matn yo‘nalishi";
|
|
114
|
+
readonly 'editor.textStyle': "Matn uslubi";
|
|
115
|
+
readonly 'editor.toolbar': "Muharrir asboblari";
|
|
116
|
+
readonly 'editor.underline': "Tagiga chizilgan";
|
|
117
|
+
readonly 'editor.undo': "Bekor qilish";
|
|
118
|
+
readonly 'editor.unlink': "Havolani olib tashlash";
|
|
119
|
+
readonly 'editor.uploadImage': "Kompyuterdan yuklash";
|
|
120
|
+
readonly 'editor.uploading': "Rasm yuklanmoqda…";
|
|
121
|
+
readonly 'editor.view.page': "Sahifa ko‘rinishi";
|
|
122
|
+
readonly 'editor.view.web': "Veb ko‘rinish";
|
|
123
|
+
readonly 'editor.zoom': "Masshtab";
|
|
124
|
+
readonly 'editor.zoomIn': "Kattalashtirish";
|
|
125
|
+
readonly 'editor.zoomOut': "Kichraytirish";
|
|
126
|
+
readonly 'editor.zoomReset': "100% ga qaytarish";
|
|
127
|
+
};
|
|
128
|
+
/** Every label key the editor uses. */
|
|
129
|
+
export type EditorLabelKey = keyof typeof MESSAGES;
|
|
130
|
+
/** Built-in label texts by key; `{name}` marks a placeholder filled in at translation time. */
|
|
131
|
+
export declare const editorMessages: Readonly<Record<EditorLabelKey, string>>;
|
|
132
|
+
/**
|
|
133
|
+
* Translates an editor label into the app's language; returning `undefined` keeps the built-in text.
|
|
134
|
+
*
|
|
135
|
+
* @param named Values for `{name}` placeholders in the message.
|
|
136
|
+
*/
|
|
137
|
+
export type EditorTranslator = (key: EditorLabelKey, named?: Record<string, unknown>) => string | undefined;
|
|
138
|
+
/** Registers the translator used for every editor label; calling it without arguments restores the built-in texts. */
|
|
139
|
+
export declare const setEditorTranslator: (next?: EditorTranslator) => void;
|
|
140
|
+
/**
|
|
141
|
+
* Translates an editor label, falling back to the built-in Uzbek text while the key has no translation.
|
|
142
|
+
*
|
|
143
|
+
* @param named Values for `{name}` placeholders in the message.
|
|
144
|
+
*/
|
|
145
|
+
export declare const t: (key: EditorLabelKey, named?: Record<string, unknown>) => string;
|
|
146
|
+
/** Formats a shortcut written as `Mod+Shift+K` for the current platform (`Ctrl+Shift+K` or `⌘⇧K`). */
|
|
147
|
+
export declare const formatShortcut: (shortcut: string) => string;
|
|
148
|
+
/** Label followed by its keyboard shortcut in parentheses, for button tooltips. */
|
|
149
|
+
export declare const withShortcut: (key: EditorLabelKey, shortcut: string) => string;
|
|
150
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** Supported paper formats. */
|
|
2
|
+
export type PageSizeKey = 'a3' | 'a4' | 'a5' | 'letter' | 'legal';
|
|
3
|
+
/** Paper orientation. */
|
|
4
|
+
export type PageOrientation = 'portrait' | 'landscape';
|
|
5
|
+
/** `page` shows sheets like a word processor, `web` a continuous surface. */
|
|
6
|
+
export type DocumentViewMode = 'page' | 'web';
|
|
7
|
+
/** Page margins in millimetres. */
|
|
8
|
+
export interface PageMargins {
|
|
9
|
+
/** Top margin. */
|
|
10
|
+
top: number;
|
|
11
|
+
/** Right margin. */
|
|
12
|
+
right: number;
|
|
13
|
+
/** Bottom margin. */
|
|
14
|
+
bottom: number;
|
|
15
|
+
/** Left margin. */
|
|
16
|
+
left: number;
|
|
17
|
+
}
|
|
18
|
+
/** Page setup chosen by the user; the host can persist it with `v-model:page`. */
|
|
19
|
+
export interface PageSettings {
|
|
20
|
+
/** Paper format. */
|
|
21
|
+
size: PageSizeKey;
|
|
22
|
+
/** Paper orientation. */
|
|
23
|
+
orientation: PageOrientation;
|
|
24
|
+
/** Margins in millimetres. */
|
|
25
|
+
margins: PageMargins;
|
|
26
|
+
}
|
|
27
|
+
/** Page geometry in CSS pixels, ready for layout. */
|
|
28
|
+
export interface PageMetrics {
|
|
29
|
+
/** Sheet width. */
|
|
30
|
+
width: number;
|
|
31
|
+
/** Sheet height. */
|
|
32
|
+
height: number;
|
|
33
|
+
/** Grey space between two sheets. */
|
|
34
|
+
gap: number;
|
|
35
|
+
/** Top margin. */
|
|
36
|
+
marginTop: number;
|
|
37
|
+
/** Right margin. */
|
|
38
|
+
marginRight: number;
|
|
39
|
+
/** Bottom margin. */
|
|
40
|
+
marginBottom: number;
|
|
41
|
+
/** Left margin. */
|
|
42
|
+
marginLeft: number;
|
|
43
|
+
}
|
|
44
|
+
/** Portrait dimensions of a paper format in millimetres. */
|
|
45
|
+
interface PaperSize {
|
|
46
|
+
/** Name shown in the page setup. */
|
|
47
|
+
label: string;
|
|
48
|
+
/** Portrait width. */
|
|
49
|
+
width: number;
|
|
50
|
+
/** Portrait height. */
|
|
51
|
+
height: number;
|
|
52
|
+
}
|
|
53
|
+
/** Paper sizes in millimetres (portrait). */
|
|
54
|
+
export declare const PAGE_SIZES: Record<PageSizeKey, PaperSize>;
|
|
55
|
+
/** Margin presets offered by the page setup, in millimetres; the key doubles as the label suffix. */
|
|
56
|
+
export declare const MARGIN_PRESETS: readonly [{
|
|
57
|
+
readonly key: "normal";
|
|
58
|
+
readonly margins: {
|
|
59
|
+
readonly top: 25.4;
|
|
60
|
+
readonly right: 25.4;
|
|
61
|
+
readonly bottom: 25.4;
|
|
62
|
+
readonly left: 25.4;
|
|
63
|
+
};
|
|
64
|
+
}, {
|
|
65
|
+
readonly key: "narrow";
|
|
66
|
+
readonly margins: {
|
|
67
|
+
readonly top: 12.7;
|
|
68
|
+
readonly right: 12.7;
|
|
69
|
+
readonly bottom: 12.7;
|
|
70
|
+
readonly left: 12.7;
|
|
71
|
+
};
|
|
72
|
+
}, {
|
|
73
|
+
readonly key: "moderate";
|
|
74
|
+
readonly margins: {
|
|
75
|
+
readonly top: 25.4;
|
|
76
|
+
readonly right: 19.1;
|
|
77
|
+
readonly bottom: 25.4;
|
|
78
|
+
readonly left: 19.1;
|
|
79
|
+
};
|
|
80
|
+
}, {
|
|
81
|
+
readonly key: "wide";
|
|
82
|
+
readonly margins: {
|
|
83
|
+
readonly top: 25.4;
|
|
84
|
+
readonly right: 50.8;
|
|
85
|
+
readonly bottom: 25.4;
|
|
86
|
+
readonly left: 50.8;
|
|
87
|
+
};
|
|
88
|
+
}, {
|
|
89
|
+
readonly key: "official";
|
|
90
|
+
readonly margins: {
|
|
91
|
+
readonly top: 20;
|
|
92
|
+
readonly right: 15;
|
|
93
|
+
readonly bottom: 20;
|
|
94
|
+
readonly left: 30;
|
|
95
|
+
};
|
|
96
|
+
}];
|
|
97
|
+
/** Smallest zoom in percent; low enough for an A4 sheet to fit a phone screen. */
|
|
98
|
+
export declare const ZOOM_MIN = 30;
|
|
99
|
+
/** Largest zoom in percent. */
|
|
100
|
+
export declare const ZOOM_MAX = 200;
|
|
101
|
+
/** Zoom change per step of the zoom buttons and slider, in percent. */
|
|
102
|
+
export declare const ZOOM_STEP = 10;
|
|
103
|
+
/** Default page setup: portrait A4 with normal margins. */
|
|
104
|
+
export declare const createPageSettings: () => PageSettings;
|
|
105
|
+
/** Converts page settings into pixel geometry; an unknown paper size falls back to A4. */
|
|
106
|
+
export declare const getPageMetrics: ({ size, orientation, margins }: PageSettings) => PageMetrics;
|
|
107
|
+
/** Whether two margin sets are equal, used to highlight the matching preset. */
|
|
108
|
+
export declare const isSameMargins: (a: PageMargins, b: PageMargins) => boolean;
|
|
109
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PageMetrics } from './page';
|
|
2
|
+
/** Handle returned by {@link createPagination}. */
|
|
3
|
+
export interface PaginationController {
|
|
4
|
+
/** Sets the page geometry and re-runs the layout; pass `null` to switch pagination off (web view). */
|
|
5
|
+
setMetrics: (metrics: PageMetrics | null) => void;
|
|
6
|
+
/** Requests a layout pass on the next animation frame, e.g. after the document changed. */
|
|
7
|
+
schedule: () => void;
|
|
8
|
+
/** Stops observing the document and cancels a pending layout pass. */
|
|
9
|
+
destroy: () => void;
|
|
10
|
+
}
|
|
11
|
+
/** Callbacks the pagination needs from its host. */
|
|
12
|
+
interface PaginationOptions {
|
|
13
|
+
/** Receives the number of sheets whenever it changes. */
|
|
14
|
+
onPageCount: (count: number) => void;
|
|
15
|
+
/** Whether an IME composition is in progress, during which blocks must not move. */
|
|
16
|
+
isComposing: () => boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Keeps the document laid out on sheets. Layout passes are batched to one per animation frame and re-run when the
|
|
20
|
+
* document resizes, images or fonts load, or the host schedules one after an edit.
|
|
21
|
+
*/
|
|
22
|
+
export declare const createPagination: (root: HTMLElement, options: PaginationOptions) => PaginationController;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Uploads an image and resolves with its public URL. Without a handler, images are embedded as data URLs. */
|
|
2
|
+
export type DocumentImageUploadHandler = (file: File) => Promise<string>;
|
|
3
|
+
export type DocumentMenuAction = 'source' | 'print' | 'exportHtml' | 'exportWord' | 'fullscreen';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { TextAlign, TextDirection } from './engine/blocks';
|
|
2
|
+
import { type PendingFormat } from './engine/marks';
|
|
3
|
+
/**
|
|
4
|
+
* Flat snapshot of everything the toolbar renders. Components receive this instead of the engine so they
|
|
5
|
+
* re-render only when a visible value changes, not on every keystroke.
|
|
6
|
+
*/
|
|
7
|
+
export interface EditorUiState {
|
|
8
|
+
/** Heading level of the current block, `0` for a paragraph. */
|
|
9
|
+
headingLevel: number;
|
|
10
|
+
/** Font family at the selection without quotes, empty for the document default. */
|
|
11
|
+
fontFamily: string;
|
|
12
|
+
/** Font size at the selection (e.g. `14pt`), empty for the document default. */
|
|
13
|
+
fontSize: string;
|
|
14
|
+
/** Line spacing of the current paragraph, empty for the default. */
|
|
15
|
+
lineHeight: string;
|
|
16
|
+
/** Text color at the selection, empty for the default. */
|
|
17
|
+
color: string;
|
|
18
|
+
/** Highlight color at the selection, empty when not highlighted. */
|
|
19
|
+
highlight: string;
|
|
20
|
+
/** Alignment of the current paragraph. */
|
|
21
|
+
align: TextAlign;
|
|
22
|
+
/** Writing direction of the current paragraph. */
|
|
23
|
+
direction: TextDirection;
|
|
24
|
+
/** Whether the selection is bold. */
|
|
25
|
+
bold: boolean;
|
|
26
|
+
/** Whether the selection is italic. */
|
|
27
|
+
italic: boolean;
|
|
28
|
+
/** Whether the selection is underlined. */
|
|
29
|
+
underline: boolean;
|
|
30
|
+
/** Whether the selection is struck through. */
|
|
31
|
+
strike: boolean;
|
|
32
|
+
/** Whether the selection is inline code. */
|
|
33
|
+
code: boolean;
|
|
34
|
+
/** Whether the selection is subscript. */
|
|
35
|
+
subscript: boolean;
|
|
36
|
+
/** Whether the selection is superscript. */
|
|
37
|
+
superscript: boolean;
|
|
38
|
+
/** Whether the selection is inside a link. */
|
|
39
|
+
link: boolean;
|
|
40
|
+
/** Whether the selection is in a bulleted list. */
|
|
41
|
+
bulletList: boolean;
|
|
42
|
+
/** Whether the selection is in a numbered list. */
|
|
43
|
+
orderedList: boolean;
|
|
44
|
+
/** Whether the selection is in a task list. */
|
|
45
|
+
taskList: boolean;
|
|
46
|
+
/** Whether the selection is inside a quote. */
|
|
47
|
+
blockquote: boolean;
|
|
48
|
+
/** Whether the selection is inside a code block. */
|
|
49
|
+
codeBlock: boolean;
|
|
50
|
+
/** Whether there is an undo step. */
|
|
51
|
+
canUndo: boolean;
|
|
52
|
+
/** Whether there is a redo step. */
|
|
53
|
+
canRedo: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** Everything {@link readUiState} needs to know about the editor. */
|
|
56
|
+
interface UiStateSource {
|
|
57
|
+
/** Editable document root. */
|
|
58
|
+
root: HTMLElement;
|
|
59
|
+
/** Current or last selection, `null` when the document never had one. */
|
|
60
|
+
range: Range | null;
|
|
61
|
+
/** Formatting chosen at a collapsed caret for the next typed text. */
|
|
62
|
+
pending: PendingFormat | null;
|
|
63
|
+
/** Whether there is an undo step. */
|
|
64
|
+
canUndo: boolean;
|
|
65
|
+
/** Whether there is a redo step. */
|
|
66
|
+
canRedo: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** State shown before the editor exists or while nothing is selected. */
|
|
69
|
+
export declare const EMPTY_UI_STATE: EditorUiState;
|
|
70
|
+
/** Font families compare without quotes: browsers re-serialise `'Times New Roman'` as `"Times New Roman"`. */
|
|
71
|
+
export declare const normalizeFontFamily: (value: string) => string;
|
|
72
|
+
/**
|
|
73
|
+
* Reads the toolbar state at a selection. Marks must cover the whole selection to count as active; styles and
|
|
74
|
+
* block properties come from its first text. At a collapsed caret pending formatting overrides the document.
|
|
75
|
+
*/
|
|
76
|
+
export declare const readUiState: ({ root, range, pending, canUndo, canRedo }: UiStateSource) => EditorUiState;
|
|
77
|
+
/** Shallow comparison used to skip toolbar re-renders when nothing visible changed. */
|
|
78
|
+
export declare const isSameUiState: (a: EditorUiState, b: EditorUiState) => boolean;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DocumentImageUploadHandler } from './core/types';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Places the caret at the end of the content once the editor is ready. */
|
|
4
|
+
autofocus?: boolean;
|
|
5
|
+
/** Gray space around the sheet, in pixels or any CSS length. */
|
|
6
|
+
canvasPadding?: number | string;
|
|
7
|
+
/** Makes the content read-only and disables the toolbar. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Height at which the field stops growing and starts scrolling. */
|
|
10
|
+
maxHeight?: number | string;
|
|
11
|
+
/** Largest accepted image file, in megabytes. */
|
|
12
|
+
maxImageSizeMb?: number;
|
|
13
|
+
/** Character limit; 0 means unlimited. */
|
|
14
|
+
maxLength?: number;
|
|
15
|
+
/** Smallest height of the field, including the gray space around the sheet. */
|
|
16
|
+
minHeight?: number | string;
|
|
17
|
+
/** Text shown while the field is empty. */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
/** Uploads an image and resolves with its URL; without it images are embedded as data URLs. */
|
|
20
|
+
uploadImage?: DocumentImageUploadHandler;
|
|
21
|
+
}
|
|
22
|
+
type __VLS_Props = Props;
|
|
23
|
+
type __VLS_ModelProps = {
|
|
24
|
+
/** Field value as sanitized HTML; an empty document is an empty string. */
|
|
25
|
+
modelValue?: string;
|
|
26
|
+
};
|
|
27
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
28
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
29
|
+
focus: () => any;
|
|
30
|
+
blur: () => any;
|
|
31
|
+
"update:modelValue": (value: string) => any;
|
|
32
|
+
uploadError: (error: unknown) => any;
|
|
33
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
34
|
+
onFocus?: (() => any) | undefined;
|
|
35
|
+
onBlur?: (() => any) | undefined;
|
|
36
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
37
|
+
onUploadError?: ((error: unknown) => any) | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
disabled: boolean;
|
|
40
|
+
placeholder: string;
|
|
41
|
+
autofocus: boolean;
|
|
42
|
+
minHeight: number | string;
|
|
43
|
+
maxLength: number;
|
|
44
|
+
maxHeight: number | string;
|
|
45
|
+
canvasPadding: number | string;
|
|
46
|
+
maxImageSizeMb: number;
|
|
47
|
+
uploadImage: DocumentImageUploadHandler;
|
|
48
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
49
|
+
declare const _default: typeof __VLS_export;
|
|
50
|
+
export default _default;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { n as e } from "./page-CEEleKNI.js";
|
|
2
|
+
//#region src/styles/document-content.css?inline
|
|
3
|
+
var t = ".doc-content{color:#1f2328;white-space:pre-wrap;overflow-wrap:break-word;tab-size:4;font-family:Times New Roman,Times,serif;font-size:12pt;line-height:1.5}.doc-content :is(p,h1,h2,h3,h4,h5,h6):not([dir]){unicode-bidi:plaintext}.doc-content p{margin:0 0 6pt}.doc-content h1,.doc-content h2,.doc-content h3,.doc-content h4,.doc-content h5,.doc-content h6{margin:0 0 6pt;padding-top:6pt;font-weight:700;line-height:1.25}.doc-content h1{font-size:20pt}.doc-content h2{font-size:16pt}.doc-content h3{font-size:14pt}.doc-content h4{font-size:12pt}.doc-content h5{font-size:11pt}.doc-content h6{font-size:10pt}.doc-content ul,.doc-content ol{margin:0 0 6pt;padding-left:24pt}.doc-content li>p{margin-bottom:2pt}.doc-content ul[data-type=taskList]{padding-left:2pt;list-style:none}.doc-content ul[data-type=taskList] li{align-items:flex-start;gap:6pt;display:flex}.doc-content ul[data-type=taskList] li>label{-webkit-user-select:none;user-select:none;flex:none;margin-top:.3em}.doc-content ul[data-type=taskList] li>div{flex:auto;min-width:0}.doc-content ul[data-type=taskList] li[data-checked=true]>div{color:#667085;text-decoration:line-through}.doc-content blockquote{color:#475467;border-left:3px solid #b3c5f5;margin:0 0 6pt;padding:2pt 0 2pt 12pt}.doc-content blockquote>p:last-child,.doc-content li>p:last-child,.doc-content td>p:last-child,.doc-content th>p:last-child{margin-bottom:0}.doc-content pre{white-space:pre-wrap;background:#f4f6f8;border-radius:4px;margin:0 0 6pt;padding:8pt 10pt;font-family:Consolas,Courier New,monospace;font-size:10pt;line-height:1.45}.doc-content code{background:#eef1f4;border-radius:3px;padding:1px 4px;font-family:Consolas,Courier New,monospace;font-size:.9em}.doc-content pre code{font-size:inherit;background:0 0;padding:0}.doc-content hr{border:0;border-bottom:1px solid #c4cad4;height:0;margin:0 0 6pt;padding-top:6pt}.doc-content a{color:#1d4ed8;text-decoration:underline}.doc-content mark{color:inherit;border-radius:2px;padding:0 1px}.doc-content img{max-width:100%;height:auto}.doc-content img[data-align=left]{margin:0 auto 6pt 0;display:block}.doc-content img[data-align=center]{margin:0 auto 6pt;display:block}.doc-content img[data-align=right]{margin:0 0 6pt auto;display:block}.doc-content table{border-collapse:collapse;table-layout:fixed;width:100%;margin:0 0 6pt}.doc-content td,.doc-content th{box-sizing:border-box;vertical-align:top;border:1px solid #8f99a8;min-width:1em;padding:3pt 5pt}.doc-content th{text-align:left;background:#f2f4f7;font-weight:700}.doc-content .doc-page-break{break-after:page;page-break-after:always;height:0}", n = "", r = {
|
|
4
|
+
"&": "&",
|
|
5
|
+
"<": "<",
|
|
6
|
+
">": ">",
|
|
7
|
+
"\"": """,
|
|
8
|
+
"'": "'"
|
|
9
|
+
}, i = /<div[^>]*data-type="page-break"[^>]*><\/div>/g, a = "<br clear=\"all\" style=\"page-break-before: always\">", o = /[\\/:*?"<>|]+/g, s = "document", c = 6e4, l = {
|
|
10
|
+
position: "fixed",
|
|
11
|
+
left: "-10000px",
|
|
12
|
+
top: "0",
|
|
13
|
+
width: "1px",
|
|
14
|
+
height: "1px",
|
|
15
|
+
border: "0"
|
|
16
|
+
}, u = (e) => e.replace(/[&<>"']/g, (e) => r[e] ?? e), d = ({ size: t, orientation: n, margins: r }) => {
|
|
17
|
+
let i = e[t] ?? e.a4, [a, o] = n === "portrait" ? [i.width, i.height] : [i.height, i.width];
|
|
18
|
+
return `size: ${a}mm ${o}mm; margin: ${r.top}mm ${r.right}mm ${r.bottom}mm ${r.left}mm;`;
|
|
19
|
+
}, f = (e) => e.replace(o, " ").trim() || s, p = ({ html: e, title: n, page: r }) => `<!doctype html>
|
|
20
|
+
<html lang="uz">
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="utf-8">
|
|
23
|
+
<title>${u(n)}</title>
|
|
24
|
+
<style>@page { ${d(r)} } html, body { margin: 0; background: #fff; } ${t}</style>
|
|
25
|
+
</head>
|
|
26
|
+
<body><article class="doc-content">${e}</article></body>
|
|
27
|
+
</html>`, m = ({ html: e, title: r, page: o }) => {
|
|
28
|
+
let s = e.replace(i, a);
|
|
29
|
+
return `${n}<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40">
|
|
30
|
+
<head>
|
|
31
|
+
<meta charset="utf-8">
|
|
32
|
+
<title>${u(r)}</title>
|
|
33
|
+
<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:Zoom>100</w:Zoom></w:WordDocument></xml><![endif]-->
|
|
34
|
+
<style>@page Section1 { ${d(o)} } div.Section1 { page: Section1; } ${t}</style>
|
|
35
|
+
</head>
|
|
36
|
+
<body><div class="Section1 doc-content">${s}</div></body>
|
|
37
|
+
</html>`;
|
|
38
|
+
}, h = (e, t, n) => {
|
|
39
|
+
let r = URL.createObjectURL(new Blob([e], { type: n })), i = document.createElement("a");
|
|
40
|
+
i.href = r, i.download = t, i.click(), setTimeout(() => URL.revokeObjectURL(r), 0);
|
|
41
|
+
}, g = (e) => {
|
|
42
|
+
let t = document.createElement("iframe");
|
|
43
|
+
t.setAttribute("aria-hidden", "true"), t.tabIndex = -1, Object.assign(t.style, l);
|
|
44
|
+
let n = () => t.remove();
|
|
45
|
+
t.onload = () => {
|
|
46
|
+
let e = t.contentWindow;
|
|
47
|
+
if (!e) return n();
|
|
48
|
+
let r = Array.from(e.document.images).filter((e) => !e.complete).map((e) => new Promise((t) => {
|
|
49
|
+
e.addEventListener("load", t, { once: !0 }), e.addEventListener("error", t, { once: !0 });
|
|
50
|
+
}));
|
|
51
|
+
Promise.allSettled(r).then(() => {
|
|
52
|
+
e.addEventListener("afterprint", () => setTimeout(n, 0), { once: !0 }), e.focus(), e.print(), setTimeout(n, c);
|
|
53
|
+
});
|
|
54
|
+
}, t.srcdoc = e, document.body.appendChild(t);
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
export { p as buildPrintableHtml, m as buildWordHtml, h as downloadFile, g as printHtml, f as toFileName };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=export-cyOnlakM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-cyOnlakM.js","names":[],"sources":["../src/styles/document-content.css?inline","../src/core/export.ts"],"sourcesContent":["/*\n * Typography of the document itself. Shared by the editor page, print output and Word/HTML export,\n * so every rule is plain CSS scoped to `.doc-content`. Vertical rhythm uses bottom margins only:\n * no margin collapsing keeps page layout measurements exact.\n */\n\n/* Base text. Typed spaces are content, so they are kept exactly. */\n.doc-content {\n color: #1f2328;\n font-family: \"Times New Roman\", Times, serif;\n font-size: 12pt;\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-wrap: break-word;\n tab-size: 4;\n}\n\n/* Paragraphs without an explicit direction follow their own text (Arabic and Latin in one document). */\n.doc-content :is(p, h1, h2, h3, h4, h5, h6):not([dir]) {\n unicode-bidi: plaintext;\n}\n\n/* Paragraphs and headings. */\n.doc-content p {\n margin: 0 0 6pt;\n}\n\n.doc-content h1,\n.doc-content h2,\n.doc-content h3,\n.doc-content h4,\n.doc-content h5,\n.doc-content h6 {\n margin: 0 0 6pt;\n padding-top: 6pt;\n font-weight: 700;\n line-height: 1.25;\n}\n\n.doc-content h1 {\n font-size: 20pt;\n}\n\n.doc-content h2 {\n font-size: 16pt;\n}\n\n.doc-content h3 {\n font-size: 14pt;\n}\n\n.doc-content h4 {\n font-size: 12pt;\n}\n\n.doc-content h5 {\n font-size: 11pt;\n}\n\n.doc-content h6 {\n font-size: 10pt;\n}\n\n/* Lists, including task lists with a checkbox label and a content column. */\n.doc-content ul,\n.doc-content ol {\n margin: 0 0 6pt;\n padding-left: 24pt;\n}\n\n.doc-content li > p {\n margin-bottom: 2pt;\n}\n\n.doc-content ul[data-type=\"taskList\"] {\n padding-left: 2pt;\n list-style: none;\n}\n\n.doc-content ul[data-type=\"taskList\"] li {\n display: flex;\n align-items: flex-start;\n gap: 6pt;\n}\n\n.doc-content ul[data-type=\"taskList\"] li > label {\n flex: 0 0 auto;\n margin-top: 0.3em;\n user-select: none;\n}\n\n.doc-content ul[data-type=\"taskList\"] li > div {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.doc-content ul[data-type=\"taskList\"] li[data-checked=\"true\"] > div {\n color: #667085;\n text-decoration: line-through;\n}\n\n/* Quotes. */\n.doc-content blockquote {\n margin: 0 0 6pt;\n padding: 2pt 0 2pt 12pt;\n border-left: 3px solid #b3c5f5;\n color: #475467;\n}\n\n/* The last paragraph of a container adds no space below it. */\n.doc-content blockquote > p:last-child,\n.doc-content li > p:last-child,\n.doc-content td > p:last-child,\n.doc-content th > p:last-child {\n margin-bottom: 0;\n}\n\n/* Code blocks and inline code. */\n.doc-content pre {\n margin: 0 0 6pt;\n padding: 8pt 10pt;\n border-radius: 4px;\n background: #f4f6f8;\n font-family: Consolas, \"Courier New\", monospace;\n font-size: 10pt;\n line-height: 1.45;\n white-space: pre-wrap;\n}\n\n.doc-content code {\n padding: 1px 4px;\n border-radius: 3px;\n background: #eef1f4;\n font-family: Consolas, \"Courier New\", monospace;\n font-size: 0.9em;\n}\n\n.doc-content pre code {\n padding: 0;\n background: none;\n font-size: inherit;\n}\n\n/* Horizontal rule. */\n.doc-content hr {\n height: 0;\n margin: 0 0 6pt;\n padding-top: 6pt;\n border: 0;\n border-bottom: 1px solid #c4cad4;\n}\n\n/* Inline marks. */\n.doc-content a {\n color: #1d4ed8;\n text-decoration: underline;\n}\n\n.doc-content mark {\n padding: 0 1px;\n border-radius: 2px;\n color: inherit;\n}\n\n/* Images are blocks aligned through their data-align attribute. */\n.doc-content img {\n max-width: 100%;\n height: auto;\n}\n\n.doc-content img[data-align=\"left\"] {\n display: block;\n margin: 0 auto 6pt 0;\n}\n\n.doc-content img[data-align=\"center\"] {\n display: block;\n margin: 0 auto 6pt;\n}\n\n.doc-content img[data-align=\"right\"] {\n display: block;\n margin: 0 0 6pt auto;\n}\n\n/* Tables. */\n.doc-content table {\n width: 100%;\n margin: 0 0 6pt;\n border-collapse: collapse;\n table-layout: fixed;\n}\n\n.doc-content td,\n.doc-content th {\n box-sizing: border-box;\n min-width: 1em;\n padding: 3pt 5pt;\n border: 1px solid #8f99a8;\n vertical-align: top;\n}\n\n.doc-content th {\n background: #f2f4f7;\n font-weight: 700;\n text-align: left;\n}\n\n/* Manual page break: invisible in print, where it starts a new sheet. */\n.doc-content .doc-page-break {\n height: 0;\n break-after: page;\n page-break-after: always;\n}\n","import contentCss from '../styles/document-content.css?inline';\nimport { PAGE_SIZES, type PageSettings } from './page';\n\n/** Everything needed to print or export the document. */\ninterface DocumentSnapshot {\n /** Clean document HTML. */\n html: string;\n /** Document title, used for the print title and file names. */\n title: string;\n /** Page size, orientation and margins. */\n page: PageSettings;\n}\n\n/** Makes Word detect UTF-8 instead of the system code page. */\nconst BYTE_ORDER_MARK = String.fromCharCode(0xfe_ff);\n/** Characters escaped when text is placed into HTML. */\nconst HTML_ESCAPES: Record<string, string> = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\n/** Page break markup of the editor. */\nconst PAGE_BREAK_PATTERN = /<div[^>]*data-type=\"page-break\"[^>]*><\\/div>/g;\n/** Page break markup Word understands. */\nconst WORD_PAGE_BREAK = '<br clear=\"all\" style=\"page-break-before: always\">';\n/** Characters not allowed in file names on common systems. */\nconst INVALID_FILE_NAME_CHARACTERS = /[\\\\/:*?\"<>|]+/g;\n/** File name used when the title is empty. */\nconst DEFAULT_FILE_NAME = 'document';\n/** Removes the print iframe even when the browser never reports `afterprint`. */\nconst PRINT_CLEANUP_TIMEOUT_MS = 60_000;\n/** Styles that keep the print iframe out of view without `display: none`, which would stop it from printing. */\nconst HIDDEN_FRAME_STYLE: Partial<CSSStyleDeclaration> = {\n position: 'fixed',\n left: '-10000px',\n top: '0',\n width: '1px',\n height: '1px',\n border: '0'\n};\n\n/** Escapes text for use inside HTML. */\nconst escapeHtml = (value: string) => value.replace(/[&<>\"']/g, character => HTML_ESCAPES[character] ?? character);\n\n/** CSS declarations for `@page` with the paper size and margins of the page settings. */\nconst pageRule = ({ size, orientation, margins }: PageSettings) => {\n const paper = PAGE_SIZES[size] ?? PAGE_SIZES.a4;\n const [width, height] = orientation === 'portrait' ? [paper.width, paper.height] : [paper.height, paper.width];\n return `size: ${width}mm ${height}mm; margin: ${margins.top}mm ${margins.right}mm ${margins.bottom}mm ${margins.left}mm;`;\n};\n\n/** Turns a document title into a safe file name without extension. */\nexport const toFileName = (title: string): string =>\n title.replace(INVALID_FILE_NAME_CHARACTERS, ' ').trim() || DEFAULT_FILE_NAME;\n\n/** Standalone HTML with the page size and margins encoded as `@page`, used for printing and HTML export. */\nexport const buildPrintableHtml = ({ html, title, page }: DocumentSnapshot): string =>\n `<!doctype html>\n<html lang=\"uz\">\n<head>\n<meta charset=\"utf-8\">\n<title>${escapeHtml(title)}</title>\n<style>@page { ${pageRule(page)} } html, body { margin: 0; background: #fff; } ${contentCss}</style>\n</head>\n<body><article class=\"doc-content\">${html}</article></body>\n</html>`;\n\n/** Word opens HTML saved with the Office namespaces as a regular document in print layout. */\nexport const buildWordHtml = ({ html, title, page }: DocumentSnapshot): string => {\n const body = html.replace(PAGE_BREAK_PATTERN, WORD_PAGE_BREAK);\n return `${BYTE_ORDER_MARK}<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns=\"http://www.w3.org/TR/REC-html40\">\n<head>\n<meta charset=\"utf-8\">\n<title>${escapeHtml(title)}</title>\n<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:Zoom>100</w:Zoom></w:WordDocument></xml><![endif]-->\n<style>@page Section1 { ${pageRule(page)} } div.Section1 { page: Section1; } ${contentCss}</style>\n</head>\n<body><div class=\"Section1 doc-content\">${body}</div></body>\n</html>`;\n};\n\n/** Offers text content as a file download. */\nexport const downloadFile = (content: string, fileName: string, type: string): void => {\n const url = URL.createObjectURL(new Blob([content], { type }));\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n link.click();\n setTimeout(() => URL.revokeObjectURL(url), 0);\n};\n\n/** Prints through a detached iframe so the application chrome never ends up on paper. Waits for images first. */\nexport const printHtml = (documentHtml: string): void => {\n const frame = document.createElement('iframe');\n frame.setAttribute('aria-hidden', 'true');\n frame.tabIndex = -1;\n Object.assign(frame.style, HIDDEN_FRAME_STYLE);\n\n /** Removes the iframe once printing is done. */\n const cleanup = () => frame.remove();\n frame.onload = () => {\n const printWindow = frame.contentWindow;\n if (!printWindow) return cleanup();\n const pendingImages = Array.from(printWindow.document.images)\n .filter(image => !image.complete)\n .map(\n image =>\n new Promise(resolve => {\n image.addEventListener('load', resolve, { once: true });\n image.addEventListener('error', resolve, { once: true });\n })\n );\n void Promise.allSettled(pendingImages).then(() => {\n printWindow.addEventListener('afterprint', () => setTimeout(cleanup, 0), { once: true });\n printWindow.focus();\n printWindow.print();\n setTimeout(cleanup, PRINT_CLEANUP_TIMEOUT_MS);\n });\n };\n frame.srcdoc = documentHtml;\n document.body.appendChild(frame);\n};\n"],"mappings":";;yiFCcM,IAAkB,KAElB,IAAuC;CAAE,KAAK;CAAS,KAAK;CAAQ,KAAK;CAAQ,MAAK;CAAU,KAAK;AAAQ,GAE7G,IAAqB,iDAErB,IAAkB,0DAElB,IAA+B,kBAE/B,IAAoB,YAEpB,IAA2B,KAE3B,IAAmD;CACvD,UAAU;CACV,MAAM;CACN,KAAK;CACL,OAAO;CACP,QAAQ;CACR,QAAQ;AACV,GAGM,KAAc,MAAkB,EAAM,QAAQ,aAAY,MAAa,EAAa,MAAc,CAAS,GAG3G,KAAY,EAAE,SAAM,gBAAa,iBAA4B;CACjE,IAAM,IAAQ,EAAW,MAAS,EAAW,IACvC,CAAC,GAAO,KAAU,MAAgB,aAAa,CAAC,EAAM,OAAO,EAAM,MAAM,IAAI,CAAC,EAAM,QAAQ,EAAM,KAAK;CAC7G,OAAO,SAAS,EAAM,KAAK,EAAO,cAAc,EAAQ,IAAI,KAAK,EAAQ,MAAM,KAAK,EAAQ,OAAO,KAAK,EAAQ,KAAK;AACvH,GAGa,KAAc,MACzB,EAAM,QAAQ,GAA8B,GAAG,CAAC,CAAC,KAAK,KAAK,GAGhD,KAAsB,EAAE,SAAM,UAAO,cAChD;;;;SAIO,EAAW,CAAK,EAAE;iBACV,EAAS,CAAI,EAAE,iDAAiD,EAAW;;qCAEvD,EAAK;UAI7B,KAAiB,EAAE,SAAM,UAAO,cAAqC;CAChF,IAAM,IAAO,EAAK,QAAQ,GAAoB,CAAe;CAC7D,OAAO,GAAG,EAAgB;;;SAGnB,EAAW,CAAK,EAAE;;0BAED,EAAS,CAAI,EAAE,sCAAsC,EAAW;;0CAEhD,EAAK;;AAE/C,GAGa,KAAgB,GAAiB,GAAkB,MAAuB;CACrF,IAAM,IAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,CAAO,GAAG,EAAE,QAAK,CAAC,CAAC,GACvD,IAAO,SAAS,cAAc,GAAG;CAIvC,AAHA,EAAK,OAAO,GACZ,EAAK,WAAW,GAChB,EAAK,MAAM,GACX,iBAAiB,IAAI,gBAAgB,CAAG,GAAG,CAAC;AAC9C,GAGa,KAAa,MAA+B;CACvD,IAAM,IAAQ,SAAS,cAAc,QAAQ;CAG7C,AAFA,EAAM,aAAa,eAAe,MAAM,GACxC,EAAM,WAAW,IACjB,OAAO,OAAO,EAAM,OAAO,CAAkB;CAG7C,IAAM,UAAgB,EAAM,OAAO;CAqBnC,AApBA,EAAM,eAAe;EACnB,IAAM,IAAc,EAAM;EAC1B,IAAI,CAAC,GAAa,OAAO,EAAQ;EACjC,IAAM,IAAgB,MAAM,KAAK,EAAY,SAAS,MAAM,CAAC,CAC1D,QAAO,MAAS,CAAC,EAAM,QAAQ,CAAC,CAChC,KACC,MACE,IAAI,SAAQ,MAAW;GAErB,AADA,EAAM,iBAAiB,QAAQ,GAAS,EAAE,MAAM,GAAK,CAAC,GACtD,EAAM,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC;EACzD,CAAC,CACL;EACF,QAAa,WAAW,CAAa,CAAC,CAAC,WAAW;GAIhD,AAHA,EAAY,iBAAiB,oBAAoB,WAAW,GAAS,CAAC,GAAG,EAAE,MAAM,GAAK,CAAC,GACvF,EAAY,MAAM,GAClB,EAAY,MAAM,GAClB,WAAW,GAAS,CAAwB;EAC9C,CAAC;CACH,GACA,EAAM,SAAS,GACf,SAAS,KAAK,YAAY,CAAK;AACjC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API of the document editor: the editor itself, its form-field wrapper (`Editor`), page settings, the image
|
|
3
|
+
* upload contract, and label translation.
|
|
4
|
+
*/
|
|
5
|
+
export { default as DocumentEditor } from './components/document-editor.vue';
|
|
6
|
+
export type { EditorLabelKey, EditorTranslator } from './core/labels';
|
|
7
|
+
export { editorMessages, setEditorTranslator } from './core/labels';
|
|
8
|
+
export type { DocumentViewMode, PageMargins, PageOrientation, PageSettings, PageSizeKey } from './core/page';
|
|
9
|
+
export { createPageSettings } from './core/page';
|
|
10
|
+
export type { DocumentImageUploadHandler } from './core/types';
|
|
11
|
+
export { default as Editor } from './editor.vue';
|