snowkit 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,113 @@
1
+ import { renderMarkdown } from './md-render.js';
2
+ import { parseHTML } from './html.js';
3
+ import { htmlBlocks } from './docpdf-layout.js';
4
+ import { buildDocPdf } from './docpdf-render.js';
5
+
6
+ export const PDF_LIB = '/pdf-tools/pdf-lib.min.js';
7
+ export const FONTKIT = '/word-to-pdf/vendor/fontkit-1.1.1/fontkit.umd.min.js';
8
+ export const FONT_BASE = '/word-to-pdf/vendor/open-sans/';
9
+ export const FACES = { regular: 'OpenSans_400Regular', bold: 'OpenSans_700Bold', italic: 'OpenSans_400Regular_Italic', bolditalic: 'OpenSans_700Bold_Italic' };
10
+ export const BREAK_MARK = '@@page-break@@';
11
+ export const PAGE_BREAK = '\n\n' + BREAK_MARK + '\n\n';
12
+
13
+ export function markdownHtml(md) {
14
+ return renderMarkdown(String(md || '')).split('<p>' + BREAK_MARK + '</p>').join('<div style="break-before: page"></div>');
15
+ }
16
+
17
+ export function previewHtml(md) {
18
+ return renderMarkdown(String(md || ''), { headingIds: false })
19
+ .split('<p>' + BREAK_MARK + '</p>')
20
+ .join('<hr class="page-break">')
21
+ .replace(/\sstyle="[^"]*"/g, '');
22
+ }
23
+
24
+ export function markdownBlocks(md, { base = 11 } = {}) {
25
+ return htmlBlocks(parseHTML(markdownHtml(md)), { base });
26
+ }
27
+
28
+ export function joinPages(pages) {
29
+ return pages.map((p) => String(p || '').trim()).filter(Boolean).join(PAGE_BREAK);
30
+ }
31
+
32
+ export function mdEscape(text) {
33
+ return String(text == null ? '' : text)
34
+ .replace(/\r\n?/g, '\n')
35
+ .replace(/([\\`*_[\]<>#|])/g, '\\$1')
36
+ .replace(/^(\s*)(\d+)([.)])(\s)/gm, '$1$2\\$3$4')
37
+ .replace(/^(\s*)([-+])(\s)/gm, '$1\\$2$3');
38
+ }
39
+
40
+ export const PREFS_KEY = 'kittybin:prefs';
41
+
42
+ export function preferredPaper(storage) {
43
+ try {
44
+ const s = storage === undefined ? globalThis.localStorage : storage;
45
+ const p = s ? JSON.parse(s.getItem(PREFS_KEY) || '{}') : {};
46
+ return p && (p.paper === 'a4' || p.paper === 'letter') ? p.paper : '';
47
+ } catch {
48
+ return '';
49
+ }
50
+ }
51
+
52
+ export function pageSizeFor(locale, storage) {
53
+ return preferredPaper(storage) || (/^(en-us|en-ca|es-mx|es-us|fr-ca|en-ph)$/i.test(String(locale || '')) ? 'letter' : 'a4');
54
+ }
55
+
56
+ export function safeFileName(text, fallback = 'document') {
57
+ const s = String(text || '').replace(/[\\/:*?"<>|\u0000-\u001f]+/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 80);
58
+ return s || fallback;
59
+ }
60
+
61
+ let cached = null;
62
+
63
+ function loadScript(src) {
64
+ return new Promise((resolve, reject) => {
65
+ const s = document.createElement('script');
66
+ s.src = src;
67
+ s.onload = resolve;
68
+ s.onerror = () => reject(new Error('The PDF maker could not be loaded. Reload the page and try again.'));
69
+ document.head.append(s);
70
+ });
71
+ }
72
+
73
+ export async function pdfLibs() {
74
+ if (cached) return cached;
75
+ await Promise.all([window.PDFLib ? null : loadScript(PDF_LIB), window.fontkit ? null : loadScript(FONTKIT).catch(() => null)]);
76
+ let fontBytes = null;
77
+ if (window.fontkit) {
78
+ try {
79
+ const entries = await Promise.all(
80
+ Object.entries(FACES).map(async ([k, n]) => {
81
+ const r = await fetch(FONT_BASE + n + '.ttf');
82
+ if (!r.ok) throw new Error('font');
83
+ return [k, new Uint8Array(await r.arrayBuffer())];
84
+ })
85
+ );
86
+ fontBytes = Object.fromEntries(entries);
87
+ } catch (e) {
88
+ fontBytes = null;
89
+ }
90
+ }
91
+ cached = { L: window.PDFLib, fontkit: window.fontkit || null, fontBytes };
92
+ return cached;
93
+ }
94
+
95
+ export async function markdownPdf(md, opts = {}, libs = null) {
96
+ const { L, fontkit, fontBytes } = libs || (await pdfLibs());
97
+ const blocks = markdownBlocks(md, { base: opts.base || 11 });
98
+ return buildDocPdf(L, blocks, { page: opts.page || 'a4', margin: opts.margin || 56, base: opts.base || 11, numbers: !!opts.numbers, title: opts.title || '', fontkit, fontBytes });
99
+ }
100
+
101
+ export function download(data, name, type) {
102
+ const blob = data instanceof Blob ? data : new Blob([data], { type: type || 'application/octet-stream' });
103
+ const url = URL.createObjectURL(blob);
104
+ const a = document.createElement('a');
105
+ a.href = url;
106
+ a.download = name;
107
+ a.hidden = true;
108
+ document.body.append(a);
109
+ a.click();
110
+ a.remove();
111
+ setTimeout(() => URL.revokeObjectURL(url), 60000);
112
+ return name;
113
+ }