@embedpdf/web 3.0.0-next.15 → 3.0.0-next.16

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/dist/index.js CHANGED
@@ -104,6 +104,263 @@ function browserClock() {
104
104
  return clock;
105
105
  }
106
106
  //#endregion
107
+ //#region src/printer.ts
108
+ /** The attribute that marks the sheets printed from the page itself. */
109
+ const PRINT_ROOT = "data-epdf-print";
110
+ /** The browser's printer: it prints PDFs where the browser's own PDF viewer does. */
111
+ function browserPrinter() {
112
+ const printer = {
113
+ needsTap: printsOnlyFromATap(),
114
+ stage: stageSheets
115
+ };
116
+ if (!printsPdfFiles()) return printer;
117
+ let removePrinted = null;
118
+ return {
119
+ ...printer,
120
+ async stagePdf(pdf, { name, signal }) {
121
+ removePrinted?.();
122
+ removePrinted = null;
123
+ const frame = await loadPdfFrame(pdf, name, signal);
124
+ let printed = false;
125
+ return {
126
+ async print() {
127
+ frame.view.focus();
128
+ frame.view.print();
129
+ printed = true;
130
+ },
131
+ dispose() {
132
+ if (printed) removePrinted = frame.remove;
133
+ else frame.remove();
134
+ }
135
+ };
136
+ }
137
+ };
138
+ }
139
+ /** The sheets staged where this browser prints them: from the page on iOS, else a frame. */
140
+ async function stageSheets(sheets, { name, signal }) {
141
+ const urls = sheets.map((sheet) => URL.createObjectURL(sheet.image));
142
+ const revoke = () => urls.forEach((url) => URL.revokeObjectURL(url));
143
+ try {
144
+ return printsFramesAsPictures() ? await stageInPage(sheets, urls, name, revoke, signal) : await stageInFrame(sheets, urls, name, revoke, signal);
145
+ } catch (error) {
146
+ revoke();
147
+ throw error;
148
+ }
149
+ }
150
+ /** `pdf` loaded in a hidden frame of its own, where the browser's PDF viewer shows it. */
151
+ async function loadPdfFrame(pdf, name, signal) {
152
+ const url = URL.createObjectURL(new Blob([pdf], { type: "application/pdf" }));
153
+ const frame = hiddenFrame();
154
+ frame.title = name;
155
+ frame.src = url;
156
+ const remove = () => {
157
+ frame.remove();
158
+ URL.revokeObjectURL(url);
159
+ };
160
+ const loaded = untilEvent(frame, "load", signal);
161
+ document.body.appendChild(frame);
162
+ try {
163
+ await loaded;
164
+ const view = frame.contentWindow;
165
+ if (!view) throw new Error("the print frame did not load");
166
+ return {
167
+ view,
168
+ remove
169
+ };
170
+ } catch (error) {
171
+ remove();
172
+ throw error;
173
+ }
174
+ }
175
+ /**
176
+ * How the sheets print: one named `@page` per page size, and a class per size that puts a sheet
177
+ * on that page, its picture fitted inside. A browser that prints on other paper keeps each sheet
178
+ * on one page: a sheet is never taller or wider than the page it prints on. That cap is a
179
+ * percentage of the page (`html` and `body` are the page's height): Safari resolves `vw` and
180
+ * `vh` against the screen even when it prints, so on a phone they would shrink every sheet to
181
+ * the phone's width. `sizes` is each sheet's class.
182
+ */
183
+ function printSheetsStyle(sheets) {
184
+ const named = [];
185
+ const sizes = sheets.map((sheet) => {
186
+ const index = named.findIndex((other) => other.widthPt === sheet.widthPt && other.heightPt === sheet.heightPt);
187
+ return `epdf-sheet-${index >= 0 ? index : named.push(sheet) - 1}`;
188
+ });
189
+ return {
190
+ css: [
191
+ "@page { margin: 0; }",
192
+ ...named.flatMap(({ widthPt, heightPt }, index) => [`@page epdf-sheet-${index} { size: ${widthPt}pt ${heightPt}pt; margin: 0; }`, `.epdf-sheet-${index} { page: epdf-sheet-${index}; width: ${widthPt}pt; height: ${heightPt}pt; }`]),
193
+ ".epdf-print-sheet { break-after: page; break-inside: avoid; max-width: 100%; max-height: 100%; overflow: hidden; }",
194
+ ".epdf-print-sheet:last-child { break-after: auto; }",
195
+ ".epdf-print-sheet img { display: block; width: 100%; height: 100%; object-fit: contain; }"
196
+ ].join("\n"),
197
+ sizes
198
+ };
199
+ }
200
+ /** The sheets, made in `owner` (the frame's document or the page's): one per page, its picture inside. */
201
+ function sheetElements(owner, urls, sizes) {
202
+ return urls.map((url, index) => {
203
+ const sheet = owner.createElement("div");
204
+ sheet.className = `epdf-print-sheet ${sizes[index]}`;
205
+ const image = owner.createElement("img");
206
+ image.alt = "";
207
+ image.src = url;
208
+ sheet.append(image);
209
+ return sheet;
210
+ });
211
+ }
212
+ /** A frame's document before the sheets go in: nothing of the print job's own is in it. */
213
+ const FRAME_DOCUMENT = "<!doctype html><html><head><meta charset=\"utf-8\"></head><body></body></html>";
214
+ /** A frame laid out but out of sight: a frame that is not laid out may never load. */
215
+ function hiddenFrame() {
216
+ const frame = document.createElement("iframe");
217
+ frame.setAttribute("aria-hidden", "true");
218
+ frame.tabIndex = -1;
219
+ Object.assign(frame.style, {
220
+ position: "fixed",
221
+ right: "0",
222
+ bottom: "0",
223
+ width: "1px",
224
+ height: "1px",
225
+ border: "0",
226
+ opacity: "0",
227
+ pointerEvents: "none"
228
+ });
229
+ return frame;
230
+ }
231
+ /** The sheets in a hidden frame of their own, so nothing of the host page prints with them. */
232
+ async function stageInFrame(sheets, urls, name, revoke, signal) {
233
+ const { css, sizes } = printSheetsStyle(sheets);
234
+ const frame = hiddenFrame();
235
+ frame.srcdoc = FRAME_DOCUMENT;
236
+ const loaded = untilEvent(frame, "load", signal);
237
+ document.body.appendChild(frame);
238
+ try {
239
+ await loaded;
240
+ const view = frame.contentWindow;
241
+ const frameDocument = frame.contentDocument;
242
+ if (!view || !frameDocument) throw new Error("the print frame did not load");
243
+ frameDocument.title = name;
244
+ const style = frameDocument.createElement("style");
245
+ style.textContent = `html, body { margin: 0; padding: 0; height: 100%; }\n${css}`;
246
+ frameDocument.head.append(style);
247
+ frameDocument.body.append(...sheetElements(frameDocument, urls, sizes));
248
+ await decodeAll(Array.from(frameDocument.querySelectorAll("img")), signal);
249
+ return {
250
+ print: () => printFrom(view),
251
+ dispose: () => {
252
+ frame.remove();
253
+ revoke();
254
+ }
255
+ };
256
+ } catch (error) {
257
+ frame.remove();
258
+ throw error;
259
+ }
260
+ }
261
+ /**
262
+ * The sheets in the page itself, shown only when it prints, and everything else hidden then.
263
+ * While it prints, `html` and `body` are plain blocks the page's height, whatever the host page
264
+ * makes them (an app often keeps its body to the window, which would clip the sheets after the
265
+ * first). The page's title is the print job's name while it prints.
266
+ */
267
+ async function stageInPage(sheets, urls, name, revoke, signal) {
268
+ const { css, sizes } = printSheetsStyle(sheets);
269
+ const style = document.createElement("style");
270
+ style.textContent = `${css}\n@media screen { [${PRINT_ROOT}] { display: none !important; } }\n@media print { html, body { display: block !important; height: 100% !important; margin: 0 !important; padding: 0 !important; overflow: visible !important; } body > :not([${PRINT_ROOT}]) { display: none !important; } [${PRINT_ROOT}] { height: 100%; } }`;
271
+ const root = document.createElement("div");
272
+ root.setAttribute(PRINT_ROOT, "");
273
+ root.append(...sheetElements(document, urls, sizes));
274
+ document.head.appendChild(style);
275
+ document.body.appendChild(root);
276
+ const remove = () => {
277
+ root.remove();
278
+ style.remove();
279
+ };
280
+ try {
281
+ await decodeAll(Array.from(root.querySelectorAll("img")), signal);
282
+ } catch (error) {
283
+ remove();
284
+ throw error;
285
+ }
286
+ return {
287
+ async print() {
288
+ const title = document.title;
289
+ document.title = name;
290
+ try {
291
+ await printFrom(window);
292
+ } finally {
293
+ document.title = title;
294
+ }
295
+ },
296
+ dispose: () => {
297
+ remove();
298
+ revoke();
299
+ }
300
+ };
301
+ }
302
+ /** Open `view`'s print dialog; resolves when the browser says printing finished. */
303
+ function printFrom(view) {
304
+ return new Promise((resolve, reject) => {
305
+ view.addEventListener("afterprint", () => resolve(), { once: true });
306
+ try {
307
+ view.focus();
308
+ view.print();
309
+ } catch (error) {
310
+ reject(error);
311
+ }
312
+ });
313
+ }
314
+ /** Wait until every picture is decoded, so the dialog never shows an empty sheet. */
315
+ async function decodeAll(images, signal) {
316
+ await untilSettled(Promise.all(images.map((image) => image.decode())), signal);
317
+ }
318
+ function untilEvent(target, type, signal) {
319
+ return untilSettled(new Promise((resolve) => target.addEventListener(type, () => resolve(), { once: true })), signal);
320
+ }
321
+ /** `work`, or the signal's reason as soon as it aborts. */
322
+ function untilSettled(work, signal) {
323
+ if (!signal) return work;
324
+ if (signal.aborted) return Promise.reject(signal.reason);
325
+ return new Promise((resolve, reject) => {
326
+ const onAbort = () => reject(signal.reason);
327
+ signal.addEventListener("abort", onAbort, { once: true });
328
+ work.then((value) => {
329
+ signal.removeEventListener("abort", onAbort);
330
+ resolve(value);
331
+ }, (error) => {
332
+ signal.removeEventListener("abort", onAbort);
333
+ reject(error);
334
+ });
335
+ });
336
+ }
337
+ /**
338
+ * Whether this browser prints a PDF file from a frame: its own PDF viewer is on (Chrome set to
339
+ * download PDFs has none, and would download the copy instead), and it is not iOS, which reports
340
+ * a viewer but prints a framed PDF as a picture of its first page, or Android.
341
+ */
342
+ function printsPdfFiles() {
343
+ if (typeof navigator === "undefined" || navigator.pdfViewerEnabled !== true) return false;
344
+ return !printsFramesAsPictures() && !/Android/i.test(navigator.userAgent);
345
+ }
346
+ /**
347
+ * Whether this browser prints only while a tap or click is being handled: Safari's engine, whose
348
+ * vendor is Apple. On iOS a print that waited shows "This website has been blocked from
349
+ * automatically printing"; Safari on the Mac opens its print dialog, but with blank pages.
350
+ */
351
+ function printsOnlyFromATap() {
352
+ if (typeof navigator === "undefined") return false;
353
+ return navigator.vendor === "Apple Computer, Inc." || printsFramesAsPictures();
354
+ }
355
+ /**
356
+ * Whether this browser prints a frame as a picture of the page around it: every browser on
357
+ * iOS and iPadOS (all use Safari's engine; iPadOS presents itself as a Mac with touch).
358
+ */
359
+ function printsFramesAsPictures() {
360
+ if (typeof navigator === "undefined") return false;
361
+ return /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.userAgent.includes("Macintosh") && navigator.maxTouchPoints > 1;
362
+ }
363
+ //#endregion
107
364
  //#region src/css-text.ts
108
365
  /**
109
366
  * Style records as CSS text. This package hands styles out as records with
@@ -3212,8 +3469,54 @@ function chromeInPixels(nodes, page) {
3212
3469
  });
3213
3470
  }
3214
3471
  //#endregion
3472
+ //#region src/legible-text.ts
3473
+ /**
3474
+ * Editors laid out at a legible size and drawn at the page's. iOS Safari zooms the page in when
3475
+ * a field takes focus with text under 16 CSS pixels, to 16 over that size, and it reads the
3476
+ * field's own computed font size: a transform doesn't change that size (CSS `zoom` does). Text
3477
+ * on a page is drawn at the page's scale, so a form field or a text box on a phone often has
3478
+ * smaller text. Such an editor is laid out {@link legibleScaleOf} times bigger (its text, lines
3479
+ * and box alike), and a `scale()` from its top-left corner draws it back at the page's size: the
3480
+ * same picture, with text iOS reads as legible. Every other browser draws it the same way.
3481
+ */
3482
+ /** The smallest text, in CSS pixels, a field takes focus with on iOS without the page zooming in. */
3483
+ const LEGIBLE_FONT_PX = 16;
3484
+ /**
3485
+ * How many times bigger to lay out an editor whose text is `fontPx` CSS pixels, so its text is
3486
+ * at least {@link LEGIBLE_FONT_PX}: 1 when it already is.
3487
+ */
3488
+ function legibleScaleOf(fontPx) {
3489
+ return fontPx > 0 && fontPx < 16 ? 16 / fontPx : 1;
3490
+ }
3491
+ /**
3492
+ * The transform that draws an element laid out `legible` times bigger back at its size, from its
3493
+ * top-left corner (`transformOrigin: '0 0'`), or null when it is laid out at its size.
3494
+ */
3495
+ function legibleShrinkOf(legible) {
3496
+ return legible === 1 ? null : `scale(${1 / legible})`;
3497
+ }
3498
+ //#endregion
3215
3499
  //#region src/text-box-editor.ts
3216
3500
  /**
3501
+ * A free text box's editor on an element: the controller behind the
3502
+ * annotation layer's own text boxes and behind a renderer's element that
3503
+ * draws one itself. The shared rich-text binding ({@link attachRichTextEditor})
3504
+ * renders the runs as inline-styled spans, turns typing back into runs, maps
3505
+ * the selection to flat offsets and keeps the caret through a restyle; the
3506
+ * browser owns layout, the caret, input methods and the clipboard; the
3507
+ * annotation plugin owns the text, the range routing and the write after a
3508
+ * pause. This module adds what makes the element a text box of the layer:
3509
+ * focus and `contentEditable` follow the plugin's `editing`, never the other
3510
+ * way, and a press inside the box stays inside it. A framework binding keeps
3511
+ * one {@link createTextBoxEditorFollower} per element and hands it what
3512
+ * changed. {@link freeTextBoxOf} is the layer's own editor element and
3513
+ * {@link ownTextBoxOf} one a renderer draws itself, both laid out at a legible
3514
+ * size (`legible-text.ts`).
3515
+ *
3516
+ * The plugin's types are mirrored structurally, so this package stays free of
3517
+ * EmbedPDF imports.
3518
+ */
3519
+ /**
3217
3520
  * Make `element` the editor of a text box. Typing shows at once and reaches
3218
3521
  * the engine in one write after a pause (or when the edit ends), not one
3219
3522
  * write per keystroke.
@@ -3323,22 +3626,67 @@ function textBoxStyleOf(css, scale) {
3323
3626
  };
3324
3627
  }
3325
3628
  /**
3326
- * The editor element of a free text box in the page layer's pixels: the
3327
- * engine's text plate (`SetPlateRect` and its `re W n` clip), the box inset
3328
- * by its padding. Place it there with no CSS padding, so its edge is the
3329
- * plate's: CSS padding doesn't clip overflow, and scrolled lines would paint
3330
- * over the border band. The box never grows with its text.
3629
+ * The layer's own editor element for a free text box: the engine's text
3630
+ * plate (`SetPlateRect` and its `re W n` clip), the box inset by its padding,
3631
+ * with no CSS padding, so its edge is the plate's: CSS padding doesn't clip
3632
+ * overflow, and scrolled lines would paint over the border band. The box
3633
+ * never grows with its text. It is laid out at a legible size and drawn back
3634
+ * at the plate's (`legible-text.ts`), and a turned box turns about its
3635
+ * centre, as the baked appearance does. While someone types it takes the
3636
+ * pointer and shows an `outline` of that color.
3331
3637
  */
3332
- function textPlateInPixels(item, page) {
3638
+ function freeTextBoxOf(item, page, outline) {
3333
3639
  const box = rectInPixels(item.box, page);
3334
- const scale = item.box.width > 0 ? box.width / item.box.width : 1;
3335
- const inset = item.css.padding * scale;
3640
+ const onPage = item.box.width > 0 ? box.width / item.box.width : 1;
3641
+ const inset = item.css.padding * onPage;
3642
+ const width = Math.max(0, box.width - 2 * inset);
3643
+ const height = Math.max(0, box.height - 2 * inset);
3644
+ const legible = legibleScaleOf(item.css.fontSize * onPage);
3645
+ const scale = onPage * legible;
3646
+ const turn = item.rot ? `translate(${width / 2}px, ${height / 2}px) rotate(${item.rot}deg) translate(${-width / 2}px, ${-height / 2}px)` : null;
3647
+ return {
3648
+ scale,
3649
+ style: {
3650
+ position: "absolute",
3651
+ left: `${box.left + inset}px`,
3652
+ top: `${box.top + inset}px`,
3653
+ width: `${width * legible}px`,
3654
+ height: `${height * legible}px`,
3655
+ ...textBoxStyleOf(item.css, scale),
3656
+ boxSizing: "border-box",
3657
+ background: "transparent",
3658
+ whiteSpace: "pre-wrap",
3659
+ overflowWrap: "break-word",
3660
+ overflowX: "hidden",
3661
+ overflowY: item.editing ? "auto" : "hidden",
3662
+ outline: item.editing ? `${legible}px solid ${outline}` : "none",
3663
+ cursor: item.editing ? "text" : "default",
3664
+ transform: [turn, legibleShrinkOf(legible)].filter(Boolean).join(" ") || "none",
3665
+ transformOrigin: "0 0",
3666
+ pointerEvents: item.editing ? "auto" : "none"
3667
+ }
3668
+ };
3669
+ }
3670
+ /**
3671
+ * Your own element as the editor of a text box you draw yourself, at `scale`
3672
+ * pixels per point where it is ({@link textBoxEditorScaleOf}): the box's body
3673
+ * style, filling the element's parent, laid out at a legible size and drawn
3674
+ * back at the parent's (`legible-text.ts`). Draw the box's frame (its fill,
3675
+ * border and padding) on the parent: what's on the element scales with it.
3676
+ */
3677
+ function ownTextBoxOf(item, scale) {
3678
+ const legible = legibleScaleOf(item.css.fontSize * scale);
3336
3679
  return {
3337
- left: box.left + inset,
3338
- top: box.top + inset,
3339
- width: Math.max(0, box.width - 2 * inset),
3340
- height: Math.max(0, box.height - 2 * inset),
3341
- scale
3680
+ scale: scale * legible,
3681
+ style: {
3682
+ ...textBoxStyleOf(item.css, scale * legible),
3683
+ width: `${100 * legible}%`,
3684
+ height: `${100 * legible}%`,
3685
+ boxSizing: "border-box",
3686
+ transform: legibleShrinkOf(legible) ?? "none",
3687
+ transformOrigin: "0 0",
3688
+ ...item.editing ? { pointerEvents: "auto" } : {}
3689
+ }
3342
3690
  };
3343
3691
  }
3344
3692
  //#endregion
@@ -3625,19 +3973,25 @@ function cssFontOf(pdfFont) {
3625
3973
  /** Pixels per page point where the widget is drawn. */
3626
3974
  const scaleOf = (field, frame) => field.box.width > 0 ? frame.width / field.box.width : 1;
3627
3975
  /**
3628
- * A text field's editor style. A font size of 0 means "fit the box" in PDF:
3629
- * the box height for one line, Acrobat's 12 pt for several.
3976
+ * The size of a text field's text in pixels at `frame`. A font size of 0 means "fit the box" in
3977
+ * PDF: the box height for one line, Acrobat's 12 pt for several.
3630
3978
  */
3631
- function textFieldStyleOf(field, frame, colors) {
3979
+ function textFieldFontPxOf(field, frame) {
3632
3980
  const scale = scaleOf(field, frame);
3633
- const fontSize = field.look.fontSize ? field.look.fontSize * scale : field.multiline ? 12 * scale : Math.max(6, frame.height * .72);
3981
+ return field.look.fontSize ? field.look.fontSize * scale : field.multiline ? 12 * scale : Math.max(6, frame.height * .72);
3982
+ }
3983
+ /**
3984
+ * A text field's editor style at `frame`, with its lengths `legible` times bigger for an editor
3985
+ * laid out at a legible size (`legible-text.ts`).
3986
+ */
3987
+ function textFieldStyleOf(field, frame, colors, legible = 1) {
3634
3988
  return {
3635
3989
  ...cssFontOf(field.look.fontFamily),
3636
- fontSize: `${fontSize}px`,
3990
+ fontSize: `${textFieldFontPxOf(field, frame) * legible}px`,
3637
3991
  textAlign: field.look.textAlign,
3638
3992
  color: field.look.color ?? colors.text,
3639
3993
  background: field.look.background ?? colors.background,
3640
- ...field.comb && field.maxLength ? { letterSpacing: `${frame.width / field.maxLength / 2}px` } : {}
3994
+ ...field.comb && field.maxLength ? { letterSpacing: `${frame.width / field.maxLength / 2 * legible}px` } : {}
3641
3995
  };
3642
3996
  }
3643
3997
  /** A list box's style: the field's own look, the settings where it has none (12 pt for a fitted size). */
@@ -3857,6 +4211,9 @@ function widgetBoxStyleOf(widget, frame, colors, { edge = true } = {}) {
3857
4211
  * control would swallow clicks, and the box below runs the widget's action
3858
4212
  * (the read-only "button" pattern), so a disabled one lets them through.
3859
4213
  *
4214
+ * It fills the widget's box, laid out at a legible size and drawn back at the
4215
+ * box's (`legible-text.ts`), so iOS doesn't zoom the page in when it takes focus.
4216
+ *
3860
4217
  * With the engine's `layout` of the text being typed, the editor writes it
3861
4218
  * where the engine will draw it: in the engine's face (mounted), at the size
3862
4219
  * it draws (a fitted size resolved), in the box inside the border, a line of
@@ -3864,14 +4221,24 @@ function widgetBoxStyleOf(widget, frame, colors, { edge = true } = {}) {
3864
4221
  */
3865
4222
  function textFieldEditorStyleOf(field, frame, colors, focused, layout = null) {
3866
4223
  const scale = scaleOf(field, frame);
3867
- const pixels = (points) => `${points * scale}px`;
4224
+ const legible = legibleScaleOf(layout ? layout.fontSize * scale : textFieldFontPxOf(field, frame));
4225
+ const px = (pixels) => `${pixels * legible}px`;
4226
+ const pixels = (points) => px(points * scale);
3868
4227
  return {
3869
- ...FORM_CONTROL_FILL,
4228
+ position: "absolute",
4229
+ left: "0",
4230
+ top: "0",
4231
+ width: `${100 * legible}%`,
4232
+ height: `${100 * legible}%`,
4233
+ boxSizing: "border-box",
4234
+ margin: "0",
4235
+ transform: legibleShrinkOf(legible) ?? "none",
4236
+ transformOrigin: "0 0",
3870
4237
  border: "none",
3871
- outline: focused ? `2px solid ${colors.focus}` : "none",
3872
- outlineOffset: "-2px",
3873
- padding: "0 2px",
3874
- ...textFieldStyleOf(field, frame, colors),
4238
+ outline: focused ? `${px(2)} solid ${colors.focus}` : "none",
4239
+ outlineOffset: px(-2),
4240
+ padding: `0 ${px(2)}`,
4241
+ ...textFieldStyleOf(field, frame, colors, legible),
3875
4242
  ...layout ? {
3876
4243
  fontFamily: layout.fontFamily,
3877
4244
  fontWeight: layout.fontWeight,
@@ -5085,16 +5452,16 @@ function createSurfaceFocusFollower() {
5085
5452
  //#region src/standard-commands-platform.ts
5086
5453
  /**
5087
5454
  * The browser's part of the standard commands (`createStandardCommands` in
5088
- * `@embedpdf/plugin-commands/standard`): copying the selected text, handing
5089
- * the document to the user as a download, and the print dialog. Every
5090
- * framework adapter builds its `standardCommands` from this one object.
5455
+ * `@embedpdf/plugin-commands/standard`): copying the selected text, and
5456
+ * handing the document to the user as a download. Every framework adapter
5457
+ * builds its `standardCommands` from this one object. Printing is the
5458
+ * kernel's, with `browserPrinter()`.
5091
5459
  */
5092
5460
  const standardCommandsBrowser = {
5093
5461
  copySelection,
5094
- saveFile: (bytes, fileName) => saveFile(bytes, fileName, "application/pdf"),
5095
- print: () => window.print()
5462
+ saveFile: (bytes, fileName) => saveFile(bytes, fileName, "application/pdf")
5096
5463
  };
5097
5464
  //#endregion
5098
- export { EPDF_VARIABLES, FORM_CONTROL_FILL, TOOLBAR_ITEM_ATTRIBUTE, anchoredViewOf, annotationChromePaint, annotationDrawingOf, applyFirstLineShift, attachFocusTrap, attachMenuKeys, attachPagePointer, attachRichTextEditor, attachRovingFocus, attachSelectionHandle, attachTextBoxEditor, attachToolbarFocus, bakedAppearanceOf, bindCommandShortcuts, bindPaintedImage, bindWidgetEvents, browserClock, canTakeFocus, chromeInPixels, clientPageProjector, computeReleaseVelocity, containsFocus, copySelection, createClickCounter, createClickDetector, createDefaultActionsUiAdapter, createFontMounts, createOptimisticSelection, createScrollbarPresses, createShownUrls, createStageGestureController, createStageSurface, createSurfaceFocusFollower, createTextBoxEditorFollower, createTextFieldEditor, createToolbarLengths, cssFontOf, cssText, deepActiveElementOf, directionOf, editingTextKeyOf, enrichCommentThreads, epdfThemeVariables, firstLineShiftFor, fitAnchoredRect, focusablesIn, fontProgramsOf, formColorsOf, formFocusRingStyleOf, frameInPixels, ghostOpacity, hoverLink, indexedDbByteStore, installFilePickerProvider, isMacPlatform, isModifiedClick, isTabbable, isUnavailable, isUprightQuad, isolatePointerDown, isolateWheel, layerTextBoxesOf, lineModelFor, linkActivateContextOf, linkAnchorOf, linkHrefOf, listBoxControlStyleOf, listBoxStyleOf, livePageContext, loadAppearanceUrls, loadObjectUrl, lookFrameOf, lookRendererFor, makePageContext, menuItemLabelOf, mixAccent, mountFontProgram, mountWebFont, moveFocusInto, navigableLinksOf, objectUrlOf, observeAnchoredFit, observeClientGeometry, observeContentHeight, observeContentLength, observeContentWidth, observeHeight, observeLength, observeOutsidePress, observeWidth, offsetOfPosition, openExternalUri, pageClientSpace, pageLayersOf, pageSurfaceLayout, pageViewTransformInput, paint, paintDefault, partsDrawnTwice, pickFile, pickImageFile, pickRequestedFile, pictureLayerOptionsOf, pictureOrPainting, positionAnchoredRect, positionOfOffset, pressToggle, projectAnchoredTarget, quadInPixels, rasterInFrame, rectInPixels, registerRendererBehaviors, renderRichText, rendererBehaviorId, rovingMoveOf, rovingTargetOf, sameAnchoredFit, sameAnnotationAnchor, sameCreationDraftAnchor, samePageBounds, sameRotationAnchor, sameSelectionAnchor, sameSelectionEndpoints, sanitizeExternalUri, saveFile, sceneViewBox, scrollbarLayout, searchHighlightsOf, sendLinkEvent, serializeRichText, showSelectedOptions, shownAppearance, stagePageDemand, stageViewProjector, standardCommandsBrowser, styleDeltaOf, svgCursor, svgPoints, svgShapesOf, tabbablesIn, textBoxEditorScaleOf, textBoxStyleOf, textFieldEditorStyleOf, textFieldStyleOf, textPlateInPixels, toolCursorsOf, toolbarMeasureKey, toolbarStopsOf, typeaheadMatchOf, usesKey, vibrationFeedback, webFontMetrics, wheelZoomFactor, widgetBoxStyleOf, wireSelectionClipboard, wkFeedback };
5465
+ export { EPDF_VARIABLES, FORM_CONTROL_FILL, LEGIBLE_FONT_PX, TOOLBAR_ITEM_ATTRIBUTE, anchoredViewOf, annotationChromePaint, annotationDrawingOf, applyFirstLineShift, attachFocusTrap, attachMenuKeys, attachPagePointer, attachRichTextEditor, attachRovingFocus, attachSelectionHandle, attachTextBoxEditor, attachToolbarFocus, bakedAppearanceOf, bindCommandShortcuts, bindPaintedImage, bindWidgetEvents, browserClock, browserPrinter, canTakeFocus, chromeInPixels, clientPageProjector, computeReleaseVelocity, containsFocus, copySelection, createClickCounter, createClickDetector, createDefaultActionsUiAdapter, createFontMounts, createOptimisticSelection, createScrollbarPresses, createShownUrls, createStageGestureController, createStageSurface, createSurfaceFocusFollower, createTextBoxEditorFollower, createTextFieldEditor, createToolbarLengths, cssFontOf, cssText, deepActiveElementOf, directionOf, editingTextKeyOf, enrichCommentThreads, epdfThemeVariables, firstLineShiftFor, fitAnchoredRect, focusablesIn, fontProgramsOf, formColorsOf, formFocusRingStyleOf, frameInPixels, freeTextBoxOf, ghostOpacity, hoverLink, indexedDbByteStore, installFilePickerProvider, isMacPlatform, isModifiedClick, isTabbable, isUnavailable, isUprightQuad, isolatePointerDown, isolateWheel, layerTextBoxesOf, legibleScaleOf, legibleShrinkOf, lineModelFor, linkActivateContextOf, linkAnchorOf, linkHrefOf, listBoxControlStyleOf, listBoxStyleOf, livePageContext, loadAppearanceUrls, loadObjectUrl, lookFrameOf, lookRendererFor, makePageContext, menuItemLabelOf, mixAccent, mountFontProgram, mountWebFont, moveFocusInto, navigableLinksOf, objectUrlOf, observeAnchoredFit, observeClientGeometry, observeContentHeight, observeContentLength, observeContentWidth, observeHeight, observeLength, observeOutsidePress, observeWidth, offsetOfPosition, openExternalUri, ownTextBoxOf, pageClientSpace, pageLayersOf, pageSurfaceLayout, pageViewTransformInput, paint, paintDefault, partsDrawnTwice, pickFile, pickImageFile, pickRequestedFile, pictureLayerOptionsOf, pictureOrPainting, positionAnchoredRect, positionOfOffset, pressToggle, projectAnchoredTarget, quadInPixels, rasterInFrame, rectInPixels, registerRendererBehaviors, renderRichText, rendererBehaviorId, rovingMoveOf, rovingTargetOf, sameAnchoredFit, sameAnnotationAnchor, sameCreationDraftAnchor, samePageBounds, sameRotationAnchor, sameSelectionAnchor, sameSelectionEndpoints, sanitizeExternalUri, saveFile, sceneViewBox, scrollbarLayout, searchHighlightsOf, sendLinkEvent, serializeRichText, showSelectedOptions, shownAppearance, stagePageDemand, stageViewProjector, standardCommandsBrowser, styleDeltaOf, svgCursor, svgPoints, svgShapesOf, tabbablesIn, textBoxEditorScaleOf, textFieldEditorStyleOf, textFieldFontPxOf, textFieldStyleOf, toolCursorsOf, toolbarMeasureKey, toolbarStopsOf, typeaheadMatchOf, usesKey, vibrationFeedback, webFontMetrics, wheelZoomFactor, widgetBoxStyleOf, wireSelectionClipboard, wkFeedback };
5099
5466
 
5100
5467
  //# sourceMappingURL=index.js.map