@ai-matrx/office 0.8.49 → 0.8.51
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/CHANGELOG.md +22 -1
- package/dist/pdf-model.cjs +117 -3
- package/dist/pdf-model.cjs.map +1 -1
- package/dist/pdf-model.d.cts +173 -3
- package/dist/pdf-model.d.ts +173 -3
- package/dist/pdf-model.js +117 -3
- package/dist/pdf-model.js.map +1 -1
- package/dist/pdf.cjs +644 -190
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +173 -3
- package/dist/pdf.d.ts +173 -3
- package/dist/pdf.js +621 -154
- package/dist/pdf.js.map +1 -1
- package/package.json +3 -3
package/dist/pdf.cjs
CHANGED
|
@@ -32,27 +32,47 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var pdf_exports = {};
|
|
33
33
|
__export(pdf_exports, {
|
|
34
34
|
HISTORY_LIMIT: () => HISTORY_LIMIT,
|
|
35
|
+
MARKUP_KIND_LABEL: () => MARKUP_KIND_LABEL,
|
|
36
|
+
MARKUP_SIZES: () => MARKUP_SIZES,
|
|
37
|
+
MARKUP_STYLE_FIELDS: () => MARKUP_STYLE_FIELDS,
|
|
38
|
+
MARKUP_SWATCHES: () => MARKUP_SWATCHES,
|
|
35
39
|
PDF_COMING_SOON: () => PDF_COMING_SOON,
|
|
40
|
+
PDF_MARKUP_COMING_SOON: () => PDF_MARKUP_COMING_SOON,
|
|
41
|
+
PDF_MARKUP_SHORTCUTS: () => PDF_MARKUP_SHORTCUTS,
|
|
42
|
+
PDF_MARKUP_TOOLS: () => PDF_MARKUP_TOOLS,
|
|
36
43
|
PDF_SHORTCUTS: () => PDF_SHORTCUTS,
|
|
37
44
|
PDF_TOOLS: () => PDF_TOOLS,
|
|
38
45
|
PdfWorkspace: () => PdfWorkspace,
|
|
46
|
+
TIMELINE_LIMIT: () => TIMELINE_LIMIT,
|
|
39
47
|
canRedo: () => canRedo,
|
|
40
48
|
canUndo: () => canUndo,
|
|
41
49
|
comingSoonIdOf: () => comingSoonIdOf,
|
|
42
50
|
compilePageOps: () => compilePageOps,
|
|
43
51
|
deletePages: () => deletePages,
|
|
52
|
+
dropOrigin: () => dropOrigin,
|
|
53
|
+
emptyTimeline: () => emptyTimeline,
|
|
44
54
|
formatKeys: () => formatKeys,
|
|
45
55
|
freshDecisions: () => freshDecisions,
|
|
46
56
|
isDirty: () => isDirty,
|
|
47
57
|
keptOrder: () => keptOrder,
|
|
58
|
+
markupComingSoonId: () => markupComingSoonId,
|
|
59
|
+
markupRedoneElsewhere: () => markupRedoneElsewhere,
|
|
60
|
+
markupUndoneElsewhere: () => markupUndoneElsewhere,
|
|
61
|
+
matchMarkupKey: () => matchMarkupKey,
|
|
48
62
|
matchShortcut: () => matchShortcut,
|
|
63
|
+
nextRedo: () => nextRedo,
|
|
64
|
+
nextUndo: () => nextUndo,
|
|
65
|
+
pdfMarkupTool: () => pdfMarkupTool,
|
|
49
66
|
pdfTool: () => pdfTool,
|
|
50
67
|
pushStep: () => pushStep,
|
|
68
|
+
recordStep: () => recordStep,
|
|
51
69
|
redo: () => redo,
|
|
52
70
|
redoLabel: () => redoLabel,
|
|
53
71
|
reorderPages: () => reorderPages,
|
|
54
72
|
restorePages: () => restorePages,
|
|
55
73
|
startHistory: () => startHistory,
|
|
74
|
+
stepBack: () => stepBack,
|
|
75
|
+
stepForward: () => stepForward,
|
|
56
76
|
turnPages: () => turnPages,
|
|
57
77
|
undo: () => undo,
|
|
58
78
|
undoLabel: () => undoLabel
|
|
@@ -60,10 +80,10 @@ __export(pdf_exports, {
|
|
|
60
80
|
module.exports = __toCommonJS(pdf_exports);
|
|
61
81
|
|
|
62
82
|
// src/pdf/PdfWorkspace.tsx
|
|
63
|
-
var
|
|
64
|
-
var
|
|
65
|
-
var
|
|
66
|
-
var
|
|
83
|
+
var import_react4 = require("react");
|
|
84
|
+
var import_cn2 = require("@ai-matrx/design-system/cn");
|
|
85
|
+
var import_controls5 = require("@ai-matrx/design-system/controls");
|
|
86
|
+
var import_icons3 = require("@ai-matrx/design-system/icons");
|
|
67
87
|
var import_RenderedFindBar = require("@ai-matrx/rich-content/rich-document/search/RenderedFindBar");
|
|
68
88
|
|
|
69
89
|
// src/pdf/page-decisions.ts
|
|
@@ -157,6 +177,7 @@ function LeftPanel(p) {
|
|
|
157
177
|
const turn = p.decisions.turns[page] ?? 0;
|
|
158
178
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative flex h-full w-full items-center justify-center overflow-hidden bg-card", children: [
|
|
159
179
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { transform: turn ? `rotate(${turn}deg)` : void 0 }, className: "flex h-full w-full items-center justify-center", children: p.host.renderThumbnail ? p.host.renderThumbnail(page, THUMB_W) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: page }) }),
|
|
180
|
+
p.host.renderPageBadge ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pointer-events-none absolute right-1 top-1 z-10", "data-pdf-page-badge": page, children: p.host.renderPageBadge(page) }) : null,
|
|
160
181
|
page === p.currentPage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pointer-events-none absolute inset-0 border-2 border-primary" }) : null,
|
|
161
182
|
gone.has(page) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute inset-0 flex items-center justify-center bg-background/80 text-xs font-medium text-destructive", children: "Deleted" }) : null
|
|
162
183
|
] });
|
|
@@ -429,9 +450,94 @@ var canRedo = (h) => h.future.length > 0;
|
|
|
429
450
|
var undoLabel = (h) => h.present.label;
|
|
430
451
|
var redoLabel = (h) => h.future[0]?.label ?? "";
|
|
431
452
|
|
|
453
|
+
// src/pdf/markup.ts
|
|
454
|
+
var PDF_MARKUP_TOOLS = [
|
|
455
|
+
{ id: "highlight", label: "Highlight", key: "h", status: "ready", engineTool: "highlight" },
|
|
456
|
+
{ id: "freetext", label: "Text box", key: "x", status: "ready", engineTool: "freetext" },
|
|
457
|
+
{ id: "ink", label: "Draw", key: "d", status: "ready", engineTool: "ink" },
|
|
458
|
+
{ id: "image", label: "Image", key: "i", status: "ready", engineTool: "stamp" },
|
|
459
|
+
{ id: "signature", label: "Signature", key: "g", status: "ready", engineTool: "stamp", needs: "signaturePad" },
|
|
460
|
+
{ id: "underline", label: "Underline and strike out", status: "soon", reason: "The PDF writer we use makes highlights only." },
|
|
461
|
+
{ id: "shapes", label: "Shapes", status: "soon", reason: "Rectangles, ovals and arrows need their own writer." },
|
|
462
|
+
{ id: "note", label: "Sticky note", status: "soon", reason: "Comment on a highlight, text box or drawing for now." },
|
|
463
|
+
{ id: "links", label: "Links", status: "soon", reason: "The PDF writer we use cannot add or change links." },
|
|
464
|
+
{ id: "edit-text", label: "Edit page text", status: "soon", reason: "Changing the page's own text needs a server edit with a before-and-after check." }
|
|
465
|
+
];
|
|
466
|
+
var pdfMarkupTool = (id) => PDF_MARKUP_TOOLS.find((t) => t.id === id);
|
|
467
|
+
var MARKUP_SWATCHES = [
|
|
468
|
+
{ value: "#ffd400", label: "Yellow" },
|
|
469
|
+
{ value: "#5fe36b", label: "Green" },
|
|
470
|
+
{ value: "#4cc9f0", label: "Blue" },
|
|
471
|
+
{ value: "#ff6fb5", label: "Pink" },
|
|
472
|
+
{ value: "#ff4d4d", label: "Red" },
|
|
473
|
+
{ value: "#1f2937", label: "Black" }
|
|
474
|
+
];
|
|
475
|
+
var MARKUP_STYLE_FIELDS = {
|
|
476
|
+
highlight: ["color"],
|
|
477
|
+
freetext: ["color", "size"],
|
|
478
|
+
ink: ["color", "opacity", "size"],
|
|
479
|
+
stamp: [],
|
|
480
|
+
signature: []
|
|
481
|
+
};
|
|
482
|
+
var MARKUP_SIZES = {
|
|
483
|
+
freetext: [8, 10, 12, 14, 18, 24, 36],
|
|
484
|
+
ink: [1, 2, 3, 5, 8, 12]
|
|
485
|
+
};
|
|
486
|
+
var MARKUP_KIND_LABEL = {
|
|
487
|
+
highlight: "Highlight",
|
|
488
|
+
freetext: "Text box",
|
|
489
|
+
ink: "Drawing",
|
|
490
|
+
stamp: "Image",
|
|
491
|
+
signature: "Signature"
|
|
492
|
+
};
|
|
493
|
+
var MARKUP_PROMISES = {
|
|
494
|
+
underline: "Underline or strike out text, with the same colors as highlights.",
|
|
495
|
+
shapes: "Draw rectangles, ovals, lines and arrows on a page.",
|
|
496
|
+
note: "Pin a sticky note anywhere on a page.",
|
|
497
|
+
links: "Add, change and remove links to a page or a web address.",
|
|
498
|
+
"edit-text": "Change the page's own text, see a before-and-after view, then save."
|
|
499
|
+
};
|
|
500
|
+
var markupComingSoonId = (id) => id === "links" ? "pdf.links" : id === "edit-text" ? "pdf.edit-text" : `pdf.markup.${id}`;
|
|
501
|
+
var PDF_MARKUP_COMING_SOON = Object.fromEntries(
|
|
502
|
+
PDF_MARKUP_TOOLS.filter((t) => t.status === "soon").map((t) => {
|
|
503
|
+
const id = markupComingSoonId(t.id);
|
|
504
|
+
return [id, { id, label: t.label, owner: "pdf", promise: MARKUP_PROMISES[t.id] ?? "", stage: "planned", surfaces: ["PDF workspace markup panel"] }];
|
|
505
|
+
})
|
|
506
|
+
);
|
|
507
|
+
var TIMELINE_LIMIT = 100;
|
|
508
|
+
var emptyTimeline = () => ({ past: [], future: [] });
|
|
509
|
+
function recordStep(t, origin, label) {
|
|
510
|
+
return { past: [...t.past, { origin, label }].slice(-TIMELINE_LIMIT), future: [] };
|
|
511
|
+
}
|
|
512
|
+
var nextUndo = (t) => t.past[t.past.length - 1] ?? null;
|
|
513
|
+
var nextRedo = (t) => t.future[0] ?? null;
|
|
514
|
+
function stepBack(t) {
|
|
515
|
+
const last = t.past[t.past.length - 1];
|
|
516
|
+
return last ? { past: t.past.slice(0, -1), future: [last, ...t.future] } : t;
|
|
517
|
+
}
|
|
518
|
+
function stepForward(t) {
|
|
519
|
+
const next = t.future[0];
|
|
520
|
+
return next ? { past: [...t.past, next], future: t.future.slice(1) } : t;
|
|
521
|
+
}
|
|
522
|
+
function markupUndoneElsewhere(t) {
|
|
523
|
+
for (let i = t.past.length - 1; i >= 0; i--) {
|
|
524
|
+
if (t.past[i].origin === "markup") return { past: [...t.past.slice(0, i), ...t.past.slice(i + 1)], future: [t.past[i], ...t.future] };
|
|
525
|
+
}
|
|
526
|
+
return t;
|
|
527
|
+
}
|
|
528
|
+
function markupRedoneElsewhere(t) {
|
|
529
|
+
const i = t.future.findIndex((s) => s.origin === "markup");
|
|
530
|
+
if (i < 0) return t;
|
|
531
|
+
return { past: [...t.past, t.future[i]], future: [...t.future.slice(0, i), ...t.future.slice(i + 1)] };
|
|
532
|
+
}
|
|
533
|
+
function dropOrigin(t, origin) {
|
|
534
|
+
return { past: t.past.filter((s) => s.origin !== origin), future: t.future.filter((s) => s.origin !== origin) };
|
|
535
|
+
}
|
|
536
|
+
|
|
432
537
|
// src/pdf/tools.ts
|
|
433
538
|
var PDF_TOOLS = [
|
|
434
539
|
{ id: "browse", label: "Browse", key: "v", status: "ready", opens: "none", group: 0 },
|
|
540
|
+
{ id: "markup", label: "Comment and mark up", key: "m", status: "ready", capability: "client:pdfjs-annotation-editors,save-new-version", opens: "panel", group: 0, hint: "Highlight, write, draw, sign. Saves a new version." },
|
|
435
541
|
{ id: "organize", label: "Organize pages", key: "o", status: "ready", capability: "rotate-pages,delete-pages,reorder-pages", opens: "panel", group: 0 },
|
|
436
542
|
{ id: "extract-pages", label: "Extract pages", key: "e", status: "ready", capability: "extract-pages", opens: "panel", group: 0 },
|
|
437
543
|
{ id: "split", label: "Split", key: "s", status: "ready", capability: "split", opens: "panel", group: 0 },
|
|
@@ -452,7 +558,7 @@ var PDF_TOOLS = [
|
|
|
452
558
|
var pdfTool = (id) => PDF_TOOLS.find((t) => t.id === id);
|
|
453
559
|
var comingSoonIdOf = (id) => `pdf.${id}`;
|
|
454
560
|
var PROMISES = {
|
|
455
|
-
edit: "Change text and swap images
|
|
561
|
+
edit: "Change the page's own text and swap images, with a before-and-after view.",
|
|
456
562
|
forms: "Fill in a form and keep the values in the file.",
|
|
457
563
|
protect: "Lock a PDF with a password and limit what others can do.",
|
|
458
564
|
ocr: "Turn a scanned PDF into one you can search and copy from.",
|
|
@@ -477,14 +583,15 @@ var PDF_COMING_SOON = {
|
|
|
477
583
|
return [id, { id, label: t.label, owner: "pdf", promise: PROMISES[t.id] ?? "", stage: "planned", surfaces: ["PDF workspace tool rail"] }];
|
|
478
584
|
})
|
|
479
585
|
),
|
|
480
|
-
...PANEL_PROMISES
|
|
586
|
+
...PANEL_PROMISES,
|
|
587
|
+
...PDF_MARKUP_COMING_SOON
|
|
481
588
|
};
|
|
482
589
|
|
|
483
590
|
// src/pdf/shortcuts.ts
|
|
484
591
|
var PDF_SHORTCUTS = [
|
|
485
592
|
{ action: "undo", label: "Undo", keys: "Mod+Z", section: "Edit" },
|
|
486
593
|
{ action: "redo", label: "Redo", keys: "Mod+Shift+Z", section: "Edit" },
|
|
487
|
-
{ action: "save", label: "
|
|
594
|
+
{ action: "save", label: "Save markup or apply page changes", keys: "Mod+S", section: "Edit" },
|
|
488
595
|
{ action: "find", label: "Find", keys: "Mod+F", section: "Edit" },
|
|
489
596
|
{ action: "print", label: "Print", keys: "Mod+P", section: "Edit" },
|
|
490
597
|
{ action: "zoom-in", label: "Zoom in", keys: "Mod+=", section: "View" },
|
|
@@ -511,6 +618,14 @@ var PDF_SHORTCUTS = [
|
|
|
511
618
|
section: "Tools"
|
|
512
619
|
}))
|
|
513
620
|
];
|
|
621
|
+
var PDF_MARKUP_SHORTCUTS = PDF_MARKUP_TOOLS.filter(
|
|
622
|
+
(t) => t.status === "ready" && t.key
|
|
623
|
+
).map((t) => ({ tool: t.id, label: t.label, keys: t.key.toUpperCase() }));
|
|
624
|
+
function matchMarkupKey(e, typing) {
|
|
625
|
+
if (typing || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.key.length !== 1) return null;
|
|
626
|
+
const k = e.key.toLowerCase();
|
|
627
|
+
return PDF_MARKUP_SHORTCUTS.find((s) => s.keys.toLowerCase() === k)?.tool ?? null;
|
|
628
|
+
}
|
|
514
629
|
function parse(keys) {
|
|
515
630
|
const parts = keys.split("+");
|
|
516
631
|
const key = parts[parts.length - 1] === "" ? "+" : parts[parts.length - 1];
|
|
@@ -537,30 +652,222 @@ function formatKeys(keys, mac) {
|
|
|
537
652
|
return keys.split("+").map((k) => k === "Mod" ? mac ? "\u2318" : "Ctrl" : k === "Shift" ? mac ? "\u21E7" : "Shift" : k === "ArrowRight" ? "\u2192" : k === "ArrowLeft" ? "\u2190" : k).join(mac ? "" : "+");
|
|
538
653
|
}
|
|
539
654
|
|
|
540
|
-
// src/pdf/
|
|
655
|
+
// src/pdf/markup-panel.tsx
|
|
656
|
+
var import_react3 = require("react");
|
|
657
|
+
var import_cn = require("@ai-matrx/design-system/cn");
|
|
658
|
+
var import_controls4 = require("@ai-matrx/design-system/controls");
|
|
541
659
|
var import_icons = require("@ai-matrx/design-system/icons");
|
|
660
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
661
|
+
var MARKUP_ICONS = {
|
|
662
|
+
highlight: import_icons.HighlighterIcon,
|
|
663
|
+
freetext: import_icons.TypeIcon,
|
|
664
|
+
ink: import_icons.PencilIcon,
|
|
665
|
+
image: import_icons.ImageIcon,
|
|
666
|
+
signature: import_icons.PenToolIcon,
|
|
667
|
+
underline: import_icons.WrapTextIcon,
|
|
668
|
+
shapes: import_icons.ProportionsIcon,
|
|
669
|
+
note: import_icons.StickyNoteIcon,
|
|
670
|
+
links: import_icons.Link2Icon,
|
|
671
|
+
"edit-text": import_icons.TypeIcon
|
|
672
|
+
};
|
|
673
|
+
function Section({ label, children }) {
|
|
674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
676
|
+
children
|
|
677
|
+
] });
|
|
678
|
+
}
|
|
679
|
+
function StyleControls({ kind, style, onChange, compact }) {
|
|
680
|
+
const fields = MARKUP_STYLE_FIELDS[kind];
|
|
681
|
+
if (!fields.length) return null;
|
|
682
|
+
const sizes = kind === "freetext" ? MARKUP_SIZES.freetext : kind === "ink" ? MARKUP_SIZES.ink : null;
|
|
683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: (0, import_cn.cn)("flex gap-2", compact ? "items-center" : "flex-col"), children: [
|
|
684
|
+
fields.includes("color") ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.ColorSwatchRow, { colors: MARKUP_SWATCHES, value: style.color, onChange: (color) => onChange({ color }), "aria-label": "Color" }) : null,
|
|
685
|
+
fields.includes("opacity") ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: compact ? "w-52 shrink-0" : "w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.OpacitySlider, { value: style.opacity, onChange: (opacity) => onChange({ opacity }), className: "w-full" }) }) : null,
|
|
686
|
+
fields.includes("size") && sizes ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: compact ? "w-24 shrink-0" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
687
|
+
import_controls4.Select,
|
|
688
|
+
{
|
|
689
|
+
"aria-label": kind === "freetext" ? "Font size" : "Line width",
|
|
690
|
+
value: String(sizes.includes(style.size) ? style.size : sizes[0]),
|
|
691
|
+
onValueChange: (v) => onChange({ size: Number(v) }),
|
|
692
|
+
options: sizes.map((n) => ({ value: String(n), label: `${n} pt` }))
|
|
693
|
+
}
|
|
694
|
+
) }) : null
|
|
695
|
+
] });
|
|
696
|
+
}
|
|
697
|
+
function MarkupPanel({ host, engine, snapshot, active, onPick, blocked, busy, online, error, onSave, onDiscard, onSoon, goToPage, reloadKey }) {
|
|
698
|
+
const [confirmDiscard, setConfirmDiscard] = (0, import_react3.useState)(false);
|
|
699
|
+
const [signature, setSignature] = (0, import_react3.useState)(null);
|
|
700
|
+
const [existing, setExisting] = (0, import_react3.useState)(null);
|
|
701
|
+
const pending = snapshot?.pending ?? 0;
|
|
702
|
+
const tools = PDF_MARKUP_TOOLS.filter((t) => t.needs !== "signaturePad" || host.signaturePad);
|
|
703
|
+
const ready = tools.filter((t) => t.status === "ready");
|
|
704
|
+
const soon = tools.filter((t) => t.status === "soon");
|
|
705
|
+
const def = tools.find((t) => t.id === active);
|
|
706
|
+
const styleKind = def?.engineTool && def.engineTool !== "stamp" ? def.engineTool : null;
|
|
707
|
+
const Pad = host.signaturePad;
|
|
708
|
+
(0, import_react3.useEffect)(() => {
|
|
709
|
+
let live = true;
|
|
710
|
+
host.existingAnnotations?.().then((list) => live && setExisting(list), () => live && setExisting([]));
|
|
711
|
+
return () => {
|
|
712
|
+
live = false;
|
|
713
|
+
};
|
|
714
|
+
}, [host, reloadKey]);
|
|
715
|
+
(0, import_react3.useEffect)(() => {
|
|
716
|
+
if (!pending) setConfirmDiscard(false);
|
|
717
|
+
}, [pending]);
|
|
718
|
+
const pickImage = () => {
|
|
719
|
+
const input = document.createElement("input");
|
|
720
|
+
input.type = "file";
|
|
721
|
+
input.accept = "image/png,image/jpeg,image/webp,image/gif,image/svg+xml";
|
|
722
|
+
input.onchange = () => {
|
|
723
|
+
const f = input.files?.[0];
|
|
724
|
+
if (f && engine) void engine.addImage(f, "stamp");
|
|
725
|
+
};
|
|
726
|
+
input.click();
|
|
727
|
+
};
|
|
728
|
+
const row = (t) => {
|
|
729
|
+
const Icon = MARKUP_ICONS[t.id];
|
|
730
|
+
const on = t.id === active;
|
|
731
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
|
|
732
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
733
|
+
"button",
|
|
734
|
+
{
|
|
735
|
+
type: "button",
|
|
736
|
+
"aria-pressed": t.status === "ready" ? on : void 0,
|
|
737
|
+
disabled: t.status === "ready" && (!engine || Boolean(blocked)),
|
|
738
|
+
onClick: () => t.status === "soon" ? onSoon(markupComingSoonId(t.id)) : onPick(t.id),
|
|
739
|
+
className: (0, import_cn.cn)(
|
|
740
|
+
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:text-disabled-foreground",
|
|
741
|
+
on && "bg-accent"
|
|
742
|
+
),
|
|
743
|
+
children: [
|
|
744
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { className: "size-4 shrink-0" }),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "min-w-0 flex-1 truncate", children: t.label }),
|
|
746
|
+
t.status === "soon" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: "Soon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("kbd", { className: "text-muted-foreground", children: t.key?.toUpperCase() })
|
|
747
|
+
]
|
|
748
|
+
}
|
|
749
|
+
),
|
|
750
|
+
t.status === "soon" && t.reason ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pl-8 pr-2 text-xs text-muted-foreground", children: t.reason }) : null
|
|
751
|
+
] }, t.id);
|
|
752
|
+
};
|
|
753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-4", "data-pdf-markup-panel": "", children: [
|
|
754
|
+
blocked ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "status", className: "rounded-md border border-border px-2 py-1.5 text-xs", children: blocked }) : null,
|
|
755
|
+
!engine && !blocked ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Opening the document\u2026" }) : null,
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "flex flex-col", "aria-label": "Markup tools", children: ready.map(row) }),
|
|
757
|
+
styleKind && snapshot ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Section, { label: "Look", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StyleControls, { kind: styleKind, style: snapshot.styles[styleKind], onChange: (p) => engine?.setStyle(p) }) }) : null,
|
|
758
|
+
active === "highlight" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Select text on the page to highlight it." }) : null,
|
|
759
|
+
active === "freetext" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Click on the page, then type." }) : null,
|
|
760
|
+
active === "ink" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Drag on the page to draw." }) : null,
|
|
761
|
+
active === "image" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons.ImageIcon, {}), disabled: !engine, onClick: pickImage, children: "Choose an image" }) : null,
|
|
762
|
+
active === "signature" && Pad ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { label: "Signature", children: [
|
|
763
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Pad, { value: signature, onChange: setSignature }),
|
|
764
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons.PenToolIcon, {}), disabled: !engine || !signature, onClick: () => signature && engine && void engine.addImage(signature, "signature"), children: "Place on page" })
|
|
765
|
+
] }) : null,
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { label: "Changes", children: [
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs", role: "status", "data-pdf-markup-pending": "", children: pending ? `Not saved: ${snapshot?.summary}` : "No unsaved markup" }),
|
|
768
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "alert", className: "text-xs text-destructive", children: error }) : null,
|
|
769
|
+
!online ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "You are offline. Markup is kept here until you are back online." }) : null,
|
|
770
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex gap-2", children: [
|
|
771
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "primary", disabled: !pending || busy || !online, onClick: onSave, children: busy ? "Saving" : "Save" }),
|
|
772
|
+
confirmDiscard ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_controls4.Button, { variant: "outline", onClick: () => {
|
|
774
|
+
setConfirmDiscard(false);
|
|
775
|
+
onDiscard();
|
|
776
|
+
}, children: [
|
|
777
|
+
"Discard ",
|
|
778
|
+
pending
|
|
779
|
+
] }),
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "quiet", onClick: () => setConfirmDiscard(false), children: "Keep" })
|
|
781
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "outline", disabled: !pending || busy, onClick: () => setConfirmDiscard(true), children: "Discard" })
|
|
782
|
+
] })
|
|
783
|
+
] }),
|
|
784
|
+
host.existingAnnotations ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Section, { label: "In this file", children: [
|
|
785
|
+
existing === null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Reading\u2026" }) : existing.filter((a) => a.subtype !== "Link" && a.subtype !== "Widget").length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "No comments or markup yet" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "flex flex-col", "aria-label": "Annotations in this file", children: existing.filter((a) => a.subtype !== "Link" && a.subtype !== "Widget").map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", onClick: () => goToPage(a.page), className: "flex w-full items-start gap-2 rounded-md px-2 py-1 text-left text-xs hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "w-8 shrink-0 tabular-nums text-muted-foreground", children: [
|
|
787
|
+
"p. ",
|
|
788
|
+
a.page
|
|
789
|
+
] }),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "min-w-0 flex-1", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "block", children: [
|
|
792
|
+
a.subtype,
|
|
793
|
+
a.author ? ` \xB7 ${a.author}` : ""
|
|
794
|
+
] }),
|
|
795
|
+
a.contents ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "block truncate text-muted-foreground", children: a.contents }) : null
|
|
796
|
+
] })
|
|
797
|
+
] }) }, `${a.page}-${i}`)) }),
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: "Markup already saved shows on the page; changing it in place is coming." })
|
|
799
|
+
] }) : null,
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Section, { label: "Coming soon", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "flex flex-col", "aria-label": "Markup coming soon", children: soon.map(row) }) })
|
|
801
|
+
] });
|
|
802
|
+
}
|
|
803
|
+
function MarkupFloatingToolbar({ engine, snapshot, enabled, onDone }) {
|
|
804
|
+
const sel = snapshot?.selection ?? null;
|
|
805
|
+
const [commenting, setCommenting] = (0, import_react3.useState)(false);
|
|
806
|
+
const [draft, setDraft] = (0, import_react3.useState)("");
|
|
807
|
+
const selKey = sel ? `${sel.kind}:${Math.round(sel.rect.x)}:${Math.round(sel.rect.y)}` : "";
|
|
808
|
+
(0, import_react3.useEffect)(() => {
|
|
809
|
+
setCommenting(false);
|
|
810
|
+
setDraft(sel?.comment ?? "");
|
|
811
|
+
}, [selKey]);
|
|
812
|
+
if (!engine || !enabled || !sel) return null;
|
|
813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.AnchoredToolbar, { open: true, rect: sel.rect, "aria-label": `${MARKUP_KIND_LABEL[sel.kind]} options`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2", "data-pdf-markup-toolbar": "", children: [
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StyleControls, { compact: true, kind: sel.kind, style: sel.style, onChange: (p) => engine.setStyle(p) }),
|
|
815
|
+
commenting ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
816
|
+
import_controls4.Field,
|
|
817
|
+
{
|
|
818
|
+
autoFocus: true,
|
|
819
|
+
value: draft,
|
|
820
|
+
"aria-label": "Comment",
|
|
821
|
+
placeholder: "Comment",
|
|
822
|
+
onChange: (e) => setDraft(e.target.value),
|
|
823
|
+
onKeyDown: (e) => {
|
|
824
|
+
if (e.key === "Enter") {
|
|
825
|
+
engine.setComment(draft);
|
|
826
|
+
setCommenting(false);
|
|
827
|
+
onDone();
|
|
828
|
+
}
|
|
829
|
+
if (e.key === "Escape") {
|
|
830
|
+
e.stopPropagation();
|
|
831
|
+
setCommenting(false);
|
|
832
|
+
onDone();
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
onBlur: () => {
|
|
836
|
+
engine.setComment(draft);
|
|
837
|
+
setCommenting(false);
|
|
838
|
+
},
|
|
839
|
+
width: "md"
|
|
840
|
+
}
|
|
841
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons.MessageSquareIcon, {}), "aria-label": sel.comment ? "Edit comment" : "Add comment", title: sel.comment || "Add comment", pressed: Boolean(sel.comment), onClick: () => setCommenting(true) }),
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "quiet", icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons.Trash2Icon, {}), "aria-label": "Delete", title: "Delete", onClick: () => engine.deleteSelected() })
|
|
843
|
+
] }) });
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// src/pdf/tool-icons.tsx
|
|
847
|
+
var import_icons2 = require("@ai-matrx/design-system/icons");
|
|
542
848
|
var PDF_TOOL_ICONS = {
|
|
543
|
-
browse:
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
849
|
+
browse: import_icons2.HandIcon,
|
|
850
|
+
markup: import_icons2.MessageSquareIcon,
|
|
851
|
+
organize: import_icons2.LayoutGridIcon,
|
|
852
|
+
"extract-pages": import_icons2.ArrowUpFromLineIcon,
|
|
853
|
+
split: import_icons2.SplitIcon,
|
|
854
|
+
crop: import_icons2.ProportionsIcon,
|
|
855
|
+
redact: import_icons2.EraserIcon,
|
|
856
|
+
compress: import_icons2.ChevronsDownUpIcon,
|
|
857
|
+
scan: import_icons2.CameraIcon,
|
|
858
|
+
sign: import_icons2.PenToolIcon,
|
|
859
|
+
"extract-data": import_icons2.TypeIcon,
|
|
860
|
+
edit: import_icons2.PencilIcon,
|
|
861
|
+
forms: import_icons2.ListChecksIcon,
|
|
862
|
+
protect: import_icons2.LockIcon,
|
|
863
|
+
ocr: import_icons2.CaptionsIcon,
|
|
864
|
+
convert: import_icons2.ArrowLeftRightIcon,
|
|
865
|
+
compare: import_icons2.Columns2Icon,
|
|
866
|
+
stamp: import_icons2.FlagIcon
|
|
560
867
|
};
|
|
561
868
|
|
|
562
869
|
// src/pdf/PdfWorkspace.tsx
|
|
563
|
-
var
|
|
870
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
564
871
|
var ZOOM_STEPS = [0.5, 0.75, 1, 1.25, 1.5, 2, 3];
|
|
565
872
|
var COMPACT_BELOW_PX = 768;
|
|
566
873
|
var BAR = "flex h-10 shrink-0 items-center gap-1 border-b border-border bg-background px-2";
|
|
@@ -572,8 +879,8 @@ async function announceSoon(id) {
|
|
|
572
879
|
await announceComingSoon(id);
|
|
573
880
|
}
|
|
574
881
|
function useWidth(ref) {
|
|
575
|
-
const [size, setSize] = (0,
|
|
576
|
-
(0,
|
|
882
|
+
const [size, setSize] = (0, import_react4.useState)({ w: 1200, h: 800 });
|
|
883
|
+
(0, import_react4.useLayoutEffect)(() => {
|
|
577
884
|
const node = ref.current;
|
|
578
885
|
if (!node) return void 0;
|
|
579
886
|
const measure = () => setSize({ w: node.clientWidth || 1200, h: node.clientHeight || 800 });
|
|
@@ -585,36 +892,36 @@ function useWidth(ref) {
|
|
|
585
892
|
}, [ref]);
|
|
586
893
|
return size;
|
|
587
894
|
}
|
|
588
|
-
function ToolRows({ tool, hostTools, onPick }) {
|
|
589
|
-
return /* @__PURE__ */ (0,
|
|
590
|
-
hostTools.map((t) => /* @__PURE__ */ (0,
|
|
895
|
+
function ToolRows({ tool, hostTools, onPick, canMarkup = false }) {
|
|
896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
897
|
+
hostTools.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
591
898
|
"button",
|
|
592
899
|
{
|
|
593
900
|
type: "button",
|
|
594
901
|
role: "menuitem",
|
|
595
902
|
"aria-current": tool === `host:${t.id}` ? "true" : void 0,
|
|
596
|
-
className: (0,
|
|
903
|
+
className: (0, import_cn2.cn)("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", tool === `host:${t.id}` && "bg-accent"),
|
|
597
904
|
onClick: () => onPick(`host:${t.id}`),
|
|
598
905
|
children: [
|
|
599
|
-
/* @__PURE__ */ (0,
|
|
600
|
-
/* @__PURE__ */ (0,
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(t.icon, { className: "size-4 shrink-0" }),
|
|
907
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex-1 whitespace-nowrap", children: t.label })
|
|
601
908
|
]
|
|
602
909
|
}
|
|
603
910
|
) }, `host:${t.id}`)),
|
|
604
|
-
PDF_TOOLS.filter((t) => t.id !== "browse").map((t) => {
|
|
911
|
+
PDF_TOOLS.filter((t) => t.id !== "browse" && (t.id !== "markup" || canMarkup)).map((t) => {
|
|
605
912
|
const Icon = PDF_TOOL_ICONS[t.id];
|
|
606
|
-
return /* @__PURE__ */ (0,
|
|
913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
607
914
|
"button",
|
|
608
915
|
{
|
|
609
916
|
type: "button",
|
|
610
917
|
role: "menuitem",
|
|
611
918
|
"aria-current": t.id === tool ? "true" : void 0,
|
|
612
|
-
className: (0,
|
|
919
|
+
className: (0, import_cn2.cn)("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", t.id === tool && "bg-accent"),
|
|
613
920
|
onClick: () => onPick(t.id),
|
|
614
921
|
children: [
|
|
615
|
-
/* @__PURE__ */ (0,
|
|
616
|
-
/* @__PURE__ */ (0,
|
|
617
|
-
t.status === "soon" ? /* @__PURE__ */ (0,
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { className: "size-4 shrink-0" }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex-1 whitespace-nowrap", children: t.label }),
|
|
924
|
+
t.status === "soon" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-muted-foreground", children: "Coming soon" }) : null
|
|
618
925
|
]
|
|
619
926
|
}
|
|
620
927
|
) }, t.id);
|
|
@@ -622,50 +929,58 @@ function ToolRows({ tool, hostTools, onPick }) {
|
|
|
622
929
|
] });
|
|
623
930
|
}
|
|
624
931
|
function PdfWorkspace({ host, className }) {
|
|
625
|
-
const rootRef = (0,
|
|
626
|
-
const scrollerRef = (0,
|
|
932
|
+
const rootRef = (0, import_react4.useRef)(null);
|
|
933
|
+
const scrollerRef = (0, import_react4.useRef)(null);
|
|
627
934
|
const rootSize = useWidth(rootRef);
|
|
628
935
|
const viewSize = useWidth(scrollerRef);
|
|
629
936
|
const compact = rootSize.w < COMPACT_BELOW_PX;
|
|
630
937
|
const online = host.online !== false;
|
|
631
|
-
const [pageCount, setPageCount] = (0,
|
|
632
|
-
const [history, setHistory] = (0,
|
|
938
|
+
const [pageCount, setPageCount] = (0, import_react4.useState)(0);
|
|
939
|
+
const [history, setHistory] = (0, import_react4.useState)(() => startHistory(freshDecisions(0)));
|
|
633
940
|
const decisions = history.present.value;
|
|
634
941
|
const dirty = isDirty(decisions);
|
|
635
|
-
const [tool, setTool] = (0,
|
|
636
|
-
const [hostToolId, setHostToolId] = (0,
|
|
637
|
-
const hostTools = (0,
|
|
942
|
+
const [tool, setTool] = (0, import_react4.useState)("browse");
|
|
943
|
+
const [hostToolId, setHostToolId] = (0, import_react4.useState)(null);
|
|
944
|
+
const hostTools = (0, import_react4.useMemo)(() => host.tools ?? [], [host.tools]);
|
|
638
945
|
const hostTool = hostToolId ? hostTools.find((t) => t.id === hostToolId) ?? null : null;
|
|
639
946
|
const activeToolKey = hostTool ? `host:${hostTool.id}` : tool;
|
|
640
|
-
const [leftOpen, setLeftOpen] = (0,
|
|
641
|
-
const [rightOpen, setRightOpen] = (0,
|
|
642
|
-
const [leftTab, setLeftTab] = (0,
|
|
643
|
-
const [read, setRead] = (0,
|
|
644
|
-
const [spread, setSpread] = (0,
|
|
645
|
-
const [zoomMode, setZoomMode] = (0,
|
|
646
|
-
const [customZoom, setCustomZoom] = (0,
|
|
647
|
-
const [selected, setSelected] = (0,
|
|
648
|
-
const [currentPage, setCurrentPage] = (0,
|
|
649
|
-
const [pageDraft, setPageDraft] = (0,
|
|
650
|
-
const [findOpen, setFindOpen] = (0,
|
|
651
|
-
const [findFocus, setFindFocus] = (0,
|
|
652
|
-
const [pop, setPop] = (0,
|
|
653
|
-
const [sheet, setSheet] = (0,
|
|
654
|
-
const [toolQuery, setToolQuery] = (0,
|
|
655
|
-
const [busy, setBusy] = (0,
|
|
656
|
-
const [error, setError] = (0,
|
|
657
|
-
const [result, setResult] = (0,
|
|
658
|
-
const [reloadKey, setReloadKey] = (0,
|
|
659
|
-
const [sizeVersion, setSizeVersion] = (0,
|
|
660
|
-
const sizes = (0,
|
|
661
|
-
const [editingName, setEditingName] = (0,
|
|
662
|
-
const [nameDraft, setNameDraft] = (0,
|
|
663
|
-
const [printMode, setPrintMode] = (0,
|
|
664
|
-
const [printRange, setPrintRange] = (0,
|
|
665
|
-
const
|
|
947
|
+
const [leftOpen, setLeftOpen] = (0, import_react4.useState)(true);
|
|
948
|
+
const [rightOpen, setRightOpen] = (0, import_react4.useState)(true);
|
|
949
|
+
const [leftTab, setLeftTab] = (0, import_react4.useState)("pages");
|
|
950
|
+
const [read, setRead] = (0, import_react4.useState)(false);
|
|
951
|
+
const [spread, setSpread] = (0, import_react4.useState)("single");
|
|
952
|
+
const [zoomMode, setZoomMode] = (0, import_react4.useState)("fit-width");
|
|
953
|
+
const [customZoom, setCustomZoom] = (0, import_react4.useState)(1);
|
|
954
|
+
const [selected, setSelected] = (0, import_react4.useState)([]);
|
|
955
|
+
const [currentPage, setCurrentPage] = (0, import_react4.useState)(1);
|
|
956
|
+
const [pageDraft, setPageDraft] = (0, import_react4.useState)("1");
|
|
957
|
+
const [findOpen, setFindOpen] = (0, import_react4.useState)(false);
|
|
958
|
+
const [findFocus, setFindFocus] = (0, import_react4.useState)(0);
|
|
959
|
+
const [pop, setPop] = (0, import_react4.useState)(null);
|
|
960
|
+
const [sheet, setSheet] = (0, import_react4.useState)(null);
|
|
961
|
+
const [toolQuery, setToolQuery] = (0, import_react4.useState)("");
|
|
962
|
+
const [busy, setBusy] = (0, import_react4.useState)(false);
|
|
963
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
964
|
+
const [result, setResult] = (0, import_react4.useState)(null);
|
|
965
|
+
const [reloadKey, setReloadKey] = (0, import_react4.useState)(0);
|
|
966
|
+
const [sizeVersion, setSizeVersion] = (0, import_react4.useState)(0);
|
|
967
|
+
const sizes = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
|
|
968
|
+
const [editingName, setEditingName] = (0, import_react4.useState)(false);
|
|
969
|
+
const [nameDraft, setNameDraft] = (0, import_react4.useState)(host.file.name);
|
|
970
|
+
const [printMode, setPrintMode] = (0, import_react4.useState)("all");
|
|
971
|
+
const [printRange, setPrintRange] = (0, import_react4.useState)("");
|
|
972
|
+
const canMarkup = Boolean(host.saveMarkup);
|
|
973
|
+
const [engine, setEngine] = (0, import_react4.useState)(null);
|
|
974
|
+
const [snap, setSnap] = (0, import_react4.useState)(null);
|
|
975
|
+
const [timeline, setTimeline] = (0, import_react4.useState)(emptyTimeline);
|
|
976
|
+
const [markupTool, setMarkupTool] = (0, import_react4.useState)("highlight");
|
|
977
|
+
const [markupBusy, setMarkupBusy] = (0, import_react4.useState)(false);
|
|
978
|
+
const [markupError, setMarkupError] = (0, import_react4.useState)(null);
|
|
979
|
+
const markupPending = snap?.pending ?? 0;
|
|
980
|
+
const selectedPages = (0, import_react4.useMemo)(() => selected.map(Number).sort((a, b) => a - b), [selected]);
|
|
666
981
|
const toolDef = pdfTool(tool);
|
|
667
982
|
const first = sizes.current.get(1);
|
|
668
|
-
const fitPage = (0,
|
|
983
|
+
const fitPage = (0, import_react4.useMemo)(() => {
|
|
669
984
|
void sizeVersion;
|
|
670
985
|
if (!first) return 1;
|
|
671
986
|
const ratio = first.h / first.w;
|
|
@@ -674,7 +989,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
674
989
|
return clampZoom(availH * cols / (Math.max(1, viewSize.w) * ratio));
|
|
675
990
|
}, [first, spread, viewSize.h, viewSize.w, sizeVersion]);
|
|
676
991
|
const zoom = zoomMode === "fit-width" ? 1 : zoomMode === "fit-page" ? fitPage : customZoom;
|
|
677
|
-
const stepZoom = (0,
|
|
992
|
+
const stepZoom = (0, import_react4.useCallback)(
|
|
678
993
|
(dir) => {
|
|
679
994
|
const cur = zoomMode === "fit-width" ? 1 : zoomMode === "fit-page" ? fitPage : customZoom;
|
|
680
995
|
const next = dir > 0 ? ZOOM_STEPS.find((s) => s > cur + 0.01) : [...ZOOM_STEPS].reverse().find((s) => s < cur - 0.01);
|
|
@@ -684,7 +999,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
684
999
|
},
|
|
685
1000
|
[zoomMode, fitPage, customZoom]
|
|
686
1001
|
);
|
|
687
|
-
const goToPage = (0,
|
|
1002
|
+
const goToPage = (0, import_react4.useCallback)(
|
|
688
1003
|
(n) => {
|
|
689
1004
|
const page = Math.min(Math.max(1, Math.round(n)), Math.max(1, pageCount));
|
|
690
1005
|
setCurrentPage(page);
|
|
@@ -694,7 +1009,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
694
1009
|
},
|
|
695
1010
|
[pageCount]
|
|
696
1011
|
);
|
|
697
|
-
(0,
|
|
1012
|
+
(0, import_react4.useEffect)(() => {
|
|
698
1013
|
const node = scrollerRef.current;
|
|
699
1014
|
if (!node) return void 0;
|
|
700
1015
|
let raf = 0;
|
|
@@ -721,34 +1036,37 @@ function PdfWorkspace({ host, className }) {
|
|
|
721
1036
|
cancelAnimationFrame(raf);
|
|
722
1037
|
};
|
|
723
1038
|
}, [pageCount]);
|
|
724
|
-
const commit = (0,
|
|
725
|
-
|
|
726
|
-
|
|
1039
|
+
const commit = (0, import_react4.useCallback)((label, next) => {
|
|
1040
|
+
setHistory((h) => pushStep(h, label, next));
|
|
1041
|
+
setTimeline((t) => recordStep(t, "page", label));
|
|
1042
|
+
}, []);
|
|
1043
|
+
const targets = (0, import_react4.useCallback)(() => selectedPages.length ? selectedPages : [currentPage], [selectedPages, currentPage]);
|
|
1044
|
+
const turn = (0, import_react4.useCallback)(
|
|
727
1045
|
(by) => {
|
|
728
1046
|
const t = targets();
|
|
729
1047
|
commit(`Rotate ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, turnPages(decisions, t, by));
|
|
730
1048
|
},
|
|
731
1049
|
[targets, commit, decisions]
|
|
732
1050
|
);
|
|
733
|
-
const del = (0,
|
|
1051
|
+
const del = (0, import_react4.useCallback)(() => {
|
|
734
1052
|
const t = targets();
|
|
735
1053
|
commit(`Delete ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, deletePages(decisions, t));
|
|
736
1054
|
}, [targets, commit, decisions]);
|
|
737
|
-
const restore = (0,
|
|
1055
|
+
const restore = (0, import_react4.useCallback)(() => {
|
|
738
1056
|
const t = targets();
|
|
739
1057
|
commit(`Restore ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, restorePages(decisions, t));
|
|
740
1058
|
}, [targets, commit, decisions]);
|
|
741
|
-
const onDocumentLoad = (0,
|
|
1059
|
+
const onDocumentLoad = (0, import_react4.useCallback)((n) => {
|
|
742
1060
|
setPageCount(n);
|
|
743
1061
|
setHistory((h) => h.present.value.order.length === n ? h : startHistory(freshDecisions(n)));
|
|
744
1062
|
}, []);
|
|
745
|
-
const onPageSize = (0,
|
|
1063
|
+
const onPageSize = (0, import_react4.useCallback)((page, w, h) => {
|
|
746
1064
|
const prev = sizes.current.get(page);
|
|
747
1065
|
if (prev && prev.w === w && prev.h === h) return;
|
|
748
1066
|
sizes.current.set(page, { w, h });
|
|
749
1067
|
if (page === 1) queueMicrotask(() => setSizeVersion((v) => v + 1));
|
|
750
1068
|
}, []);
|
|
751
|
-
const fail = (0,
|
|
1069
|
+
const fail = (0, import_react4.useCallback)(
|
|
752
1070
|
(e) => {
|
|
753
1071
|
const message = e instanceof Error ? e.message : "That did not work.";
|
|
754
1072
|
setError(message);
|
|
@@ -756,7 +1074,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
756
1074
|
},
|
|
757
1075
|
[host]
|
|
758
1076
|
);
|
|
759
|
-
const runTool = (0,
|
|
1077
|
+
const runTool = (0, import_react4.useCallback)(
|
|
760
1078
|
async (request) => {
|
|
761
1079
|
if (!online) {
|
|
762
1080
|
setError("You are offline. Changes are not queued; try again when you are back online.");
|
|
@@ -782,12 +1100,109 @@ function PdfWorkspace({ host, className }) {
|
|
|
782
1100
|
},
|
|
783
1101
|
[host, online, pageCount, fail]
|
|
784
1102
|
);
|
|
785
|
-
const apply = (0,
|
|
1103
|
+
const apply = (0, import_react4.useCallback)(() => {
|
|
786
1104
|
const ops = compilePageOps(decisions);
|
|
787
|
-
if (ops.length)
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1105
|
+
if (!ops.length) return;
|
|
1106
|
+
if (markupPending) {
|
|
1107
|
+
setError("Save or discard your markup first: applying page changes reloads the file.");
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
setTimeline((t) => dropOrigin(t, "page"));
|
|
1111
|
+
void runTool({ tool: "apply-pages", ops });
|
|
1112
|
+
}, [decisions, runTool, markupPending]);
|
|
1113
|
+
const discard = (0, import_react4.useCallback)(() => {
|
|
1114
|
+
setHistory(startHistory(freshDecisions(pageCount)));
|
|
1115
|
+
setTimeline((t) => dropOrigin(t, "page"));
|
|
1116
|
+
}, [pageCount]);
|
|
1117
|
+
const onMarkupEngine = (0, import_react4.useCallback)((e) => {
|
|
1118
|
+
setEngine(e);
|
|
1119
|
+
setSnap(e ? e.getSnapshot() : null);
|
|
1120
|
+
}, []);
|
|
1121
|
+
(0, import_react4.useEffect)(() => {
|
|
1122
|
+
if (!engine) return void 0;
|
|
1123
|
+
const offSnap = engine.subscribe(setSnap);
|
|
1124
|
+
const offHistory = engine.onHistory((ev) => {
|
|
1125
|
+
if (ev.type === "step") setTimeline((t) => recordStep(t, "markup", ev.label));
|
|
1126
|
+
else if (ev.external) setTimeline((t) => ev.type === "undo" ? markupUndoneElsewhere(t) : markupRedoneElsewhere(t));
|
|
1127
|
+
});
|
|
1128
|
+
return () => {
|
|
1129
|
+
offSnap();
|
|
1130
|
+
offHistory();
|
|
1131
|
+
};
|
|
1132
|
+
}, [engine]);
|
|
1133
|
+
const markupOn = tool === "markup" && !hostTool && !dirty;
|
|
1134
|
+
const markupEngineTool = pdfMarkupTool(markupTool)?.engineTool ?? "highlight";
|
|
1135
|
+
(0, import_react4.useEffect)(() => {
|
|
1136
|
+
if (engine) void engine.setTool(markupOn ? markupEngineTool : "none");
|
|
1137
|
+
}, [engine, markupOn, markupEngineTool]);
|
|
1138
|
+
(0, import_react4.useEffect)(() => {
|
|
1139
|
+
engine?.setCurrentPage(currentPage);
|
|
1140
|
+
}, [engine, currentPage]);
|
|
1141
|
+
const saveMarkup = (0, import_react4.useCallback)(async () => {
|
|
1142
|
+
if (!engine || !host.saveMarkup || !markupPending || markupBusy) return;
|
|
1143
|
+
if (!online) {
|
|
1144
|
+
setMarkupError("You are offline. Your markup is kept here; save when you are back online.");
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
setMarkupBusy(true);
|
|
1148
|
+
setMarkupError(null);
|
|
1149
|
+
try {
|
|
1150
|
+
const summary = engine.getSnapshot().summary;
|
|
1151
|
+
const bytes = await engine.save();
|
|
1152
|
+
const out = await host.saveMarkup(bytes, summary);
|
|
1153
|
+
setResult(out);
|
|
1154
|
+
setTimeline((t) => dropOrigin(t, "markup"));
|
|
1155
|
+
sizes.current.clear();
|
|
1156
|
+
setReloadKey((k) => k + 1);
|
|
1157
|
+
} catch (e) {
|
|
1158
|
+
const message = e instanceof Error ? e.message : "The markup was not saved.";
|
|
1159
|
+
setMarkupError(message);
|
|
1160
|
+
host.notify?.(message, "error");
|
|
1161
|
+
} finally {
|
|
1162
|
+
setMarkupBusy(false);
|
|
1163
|
+
}
|
|
1164
|
+
}, [engine, host, markupPending, markupBusy, online]);
|
|
1165
|
+
const discardMarkup = (0, import_react4.useCallback)(() => {
|
|
1166
|
+
setTimeline((t) => dropOrigin(t, "markup"));
|
|
1167
|
+
setMarkupError(null);
|
|
1168
|
+
setReloadKey((k) => k + 1);
|
|
1169
|
+
}, []);
|
|
1170
|
+
(0, import_react4.useEffect)(() => {
|
|
1171
|
+
if (!markupPending) return void 0;
|
|
1172
|
+
const onBeforeUnload = (event) => {
|
|
1173
|
+
event.preventDefault();
|
|
1174
|
+
event.returnValue = "";
|
|
1175
|
+
};
|
|
1176
|
+
window.addEventListener("beforeunload", onBeforeUnload);
|
|
1177
|
+
return () => window.removeEventListener("beforeunload", onBeforeUnload);
|
|
1178
|
+
}, [markupPending]);
|
|
1179
|
+
const undoAll = (0, import_react4.useCallback)(() => {
|
|
1180
|
+
const step = nextUndo(timeline);
|
|
1181
|
+
if (step?.origin === "markup" && engine) {
|
|
1182
|
+
setTimeline(stepBack);
|
|
1183
|
+
engine.undo();
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
if (step) setTimeline(stepBack);
|
|
1187
|
+
setHistory((h) => undo(h));
|
|
1188
|
+
}, [timeline, engine]);
|
|
1189
|
+
const redoAll = (0, import_react4.useCallback)(() => {
|
|
1190
|
+
const step = nextRedo(timeline);
|
|
1191
|
+
if (step?.origin === "markup" && engine) {
|
|
1192
|
+
setTimeline(stepForward);
|
|
1193
|
+
engine.redo();
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (step) setTimeline(stepForward);
|
|
1197
|
+
setHistory((h) => redo(h));
|
|
1198
|
+
}, [timeline, engine]);
|
|
1199
|
+
const undoStep = nextUndo(timeline);
|
|
1200
|
+
const redoStep = nextRedo(timeline);
|
|
1201
|
+
const undoText = undoStep ? `Undo ${undoStep.label}` : undoLabel(history) ? `Undo ${undoLabel(history)}` : "Undo";
|
|
1202
|
+
const redoText = redoStep ? `Redo ${redoStep.label}` : redoLabel(history) ? `Redo ${redoLabel(history)}` : "Redo";
|
|
1203
|
+
const canUndoAll = Boolean(undoStep) || canUndo(history);
|
|
1204
|
+
const canRedoAll = Boolean(redoStep) || canRedo(history);
|
|
1205
|
+
const chooseTool = (0, import_react4.useCallback)(
|
|
791
1206
|
(id) => {
|
|
792
1207
|
if (id.startsWith("host:")) {
|
|
793
1208
|
setHostToolId(id.slice(5));
|
|
@@ -798,7 +1213,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
798
1213
|
return;
|
|
799
1214
|
}
|
|
800
1215
|
const def = pdfTool(id);
|
|
801
|
-
if (!def) return;
|
|
1216
|
+
if (!def || def.id === "markup" && !host.saveMarkup) return;
|
|
802
1217
|
setHostToolId(null);
|
|
803
1218
|
if (def.status === "soon") {
|
|
804
1219
|
announceSoon(comingSoonIdOf(def.id)).catch(fail);
|
|
@@ -816,26 +1231,26 @@ function PdfWorkspace({ host, className }) {
|
|
|
816
1231
|
},
|
|
817
1232
|
[host, compact, fail]
|
|
818
1233
|
);
|
|
819
|
-
const railGroups = (0,
|
|
1234
|
+
const railGroups = (0, import_react4.useMemo)(() => {
|
|
820
1235
|
const groups = [[], [], []];
|
|
821
1236
|
for (const t of PDF_TOOLS) {
|
|
822
|
-
if (t.status !== "ready") continue;
|
|
1237
|
+
if (t.status !== "ready" || t.id === "markup" && !canMarkup) continue;
|
|
823
1238
|
groups[t.group].push({ id: t.id, label: t.label, icon: PDF_TOOL_ICONS[t.id], ...t.key ? { shortcut: t.key.toUpperCase() } : null });
|
|
824
1239
|
}
|
|
825
1240
|
for (const t of hostTools) groups[t.group ?? 1].push({ id: `host:${t.id}`, label: t.label, icon: t.icon });
|
|
826
|
-
groups[2].push({ id: ALL_TOOLS, label: "All tools", icon:
|
|
1241
|
+
groups[2].push({ id: ALL_TOOLS, label: "All tools", icon: import_icons3.MoreHorizontalIcon });
|
|
827
1242
|
return groups.filter((g) => g.length);
|
|
828
|
-
}, [hostTools]);
|
|
829
|
-
const runAction = (0,
|
|
1243
|
+
}, [hostTools, canMarkup]);
|
|
1244
|
+
const runAction = (0, import_react4.useCallback)(
|
|
830
1245
|
(action) => {
|
|
831
1246
|
if (action.startsWith("tool:")) return chooseTool(action.slice(5));
|
|
832
1247
|
switch (action) {
|
|
833
1248
|
case "undo":
|
|
834
|
-
return
|
|
1249
|
+
return undoAll();
|
|
835
1250
|
case "redo":
|
|
836
|
-
return
|
|
1251
|
+
return redoAll();
|
|
837
1252
|
case "save":
|
|
838
|
-
return apply();
|
|
1253
|
+
return markupPending ? void saveMarkup() : apply();
|
|
839
1254
|
case "find":
|
|
840
1255
|
setFindOpen(true);
|
|
841
1256
|
setFindFocus((n) => n + 1);
|
|
@@ -880,7 +1295,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
880
1295
|
return void 0;
|
|
881
1296
|
}
|
|
882
1297
|
},
|
|
883
|
-
[chooseTool, apply, host.print, stepZoom, goToPage, currentPage, pageCount, turn, del, decisions.order]
|
|
1298
|
+
[chooseTool, apply, host.print, stepZoom, goToPage, currentPage, pageCount, turn, del, decisions.order, undoAll, redoAll, markupPending, saveMarkup]
|
|
884
1299
|
);
|
|
885
1300
|
const onKeyDown = (e) => {
|
|
886
1301
|
const t = e.target;
|
|
@@ -892,19 +1307,30 @@ function PdfWorkspace({ host, className }) {
|
|
|
892
1307
|
else if (sheet) setSheet(null);
|
|
893
1308
|
return;
|
|
894
1309
|
}
|
|
1310
|
+
if (markupOn) {
|
|
1311
|
+
const pick = matchMarkupKey(e.nativeEvent, typing);
|
|
1312
|
+
if (pick && pdfMarkupTool(pick)?.status === "ready" && (pick !== "signature" || host.signaturePad)) {
|
|
1313
|
+
e.preventDefault();
|
|
1314
|
+
setMarkupTool(pick);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
895
1318
|
const action = matchShortcut(e.nativeEvent, typing);
|
|
896
1319
|
if (!action) return;
|
|
1320
|
+
if (markupOn && t.closest("[data-pdf-thumbnails]") === null && (action === "delete-pages" || action === "page-next" || action === "page-prev" || action === "select-all-pages")) return;
|
|
897
1321
|
if ((action === "page-next" || action === "page-prev") && t !== scrollerRef.current && t !== rootRef.current) return;
|
|
898
1322
|
if (action === "delete-pages" && t.closest("[data-pdf-thumbnails]") === null && t !== scrollerRef.current) return;
|
|
899
1323
|
e.preventDefault();
|
|
1324
|
+
if (action === "undo" || action === "redo") e.stopPropagation();
|
|
900
1325
|
runAction(action);
|
|
901
1326
|
};
|
|
902
|
-
const
|
|
903
|
-
const
|
|
1327
|
+
const unsaved = dirty || markupPending > 0;
|
|
1328
|
+
const saveState = !online ? "Offline" : busy || markupBusy ? "Saving" : error && dirty || markupError && markupPending ? "Not saved" : unsaved ? "Unsaved" : "Saved";
|
|
1329
|
+
const savePill = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
904
1330
|
"span",
|
|
905
1331
|
{
|
|
906
1332
|
role: "status",
|
|
907
|
-
className: (0,
|
|
1333
|
+
className: (0, import_cn2.cn)(
|
|
908
1334
|
"inline-flex h-6 shrink-0 items-center justify-center whitespace-nowrap rounded-full border px-2 text-xs",
|
|
909
1335
|
saveState === "Unsaved" || saveState === "Offline" || saveState === "Not saved" ? "border-border text-foreground" : "border-border text-muted-foreground",
|
|
910
1336
|
busy && "animate-pulse"
|
|
@@ -912,13 +1338,13 @@ function PdfWorkspace({ host, className }) {
|
|
|
912
1338
|
children: saveState
|
|
913
1339
|
}
|
|
914
1340
|
);
|
|
915
|
-
const iconBtn = (label, icon, onClick, opts) => /* @__PURE__ */ (0,
|
|
1341
|
+
const iconBtn = (label, icon, onClick, opts) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.Button, { variant: "quiet", icon, "aria-label": label, title: label, onClick, ...opts?.disabled !== void 0 ? { disabled: opts.disabled } : null, ...opts?.pressed !== void 0 ? { pressed: opts.pressed } : null });
|
|
916
1342
|
const toolHits = toolQuery.trim() ? [
|
|
917
1343
|
...hostTools.map((t) => ({ id: `host:${t.id}`, label: t.label, status: "ready" })),
|
|
918
1344
|
...PDF_TOOLS
|
|
919
1345
|
].filter((t) => t.label.toLowerCase().includes(toolQuery.trim().toLowerCase())) : [];
|
|
920
|
-
const nameNode = editingName && host.rename ? /* @__PURE__ */ (0,
|
|
921
|
-
|
|
1346
|
+
const nameNode = editingName && host.rename ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1347
|
+
import_controls5.Field,
|
|
922
1348
|
{
|
|
923
1349
|
autoFocus: true,
|
|
924
1350
|
value: nameDraft,
|
|
@@ -937,7 +1363,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
937
1363
|
},
|
|
938
1364
|
width: "lg"
|
|
939
1365
|
}
|
|
940
|
-
) : /* @__PURE__ */ (0,
|
|
1366
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
941
1367
|
"button",
|
|
942
1368
|
{
|
|
943
1369
|
type: "button",
|
|
@@ -947,18 +1373,36 @@ function PdfWorkspace({ host, className }) {
|
|
|
947
1373
|
children: host.file.name
|
|
948
1374
|
}
|
|
949
1375
|
);
|
|
950
|
-
const rightPanel = hostTool ? /* @__PURE__ */ (0,
|
|
951
|
-
/* @__PURE__ */ (0,
|
|
952
|
-
/* @__PURE__ */ (0,
|
|
953
|
-
hostTool.hint ? /* @__PURE__ */ (0,
|
|
1376
|
+
const rightPanel = hostTool ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex h-full min-h-0 flex-col", "data-pdf-host-tool": hostTool.id, children: [
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "shrink-0 border-b border-border px-3 py-2", children: [
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-sm font-medium", children: hostTool.label }),
|
|
1379
|
+
hostTool.hint ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-xs text-muted-foreground", children: hostTool.hint }) : null
|
|
954
1380
|
] }),
|
|
955
|
-
/* @__PURE__ */ (0,
|
|
956
|
-
] }) : /* @__PURE__ */ (0,
|
|
957
|
-
/* @__PURE__ */ (0,
|
|
958
|
-
/* @__PURE__ */ (0,
|
|
959
|
-
toolDef.hint ? /* @__PURE__ */ (0,
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-h-0 flex-1 overflow-hidden", children: hostTool.render({ currentPage, pageCount, selected: selectedPages, goToPage, reload: () => setReloadKey((k) => k + 1) }) })
|
|
1382
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "shrink-0 border-b border-border px-3 py-2", children: [
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-sm font-medium", children: toolDef.label }),
|
|
1385
|
+
toolDef.hint ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-xs text-muted-foreground", children: toolDef.hint }) : null
|
|
960
1386
|
] }),
|
|
961
|
-
/* @__PURE__ */ (0,
|
|
1387
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto p-3", children: tool === "markup" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1388
|
+
MarkupPanel,
|
|
1389
|
+
{
|
|
1390
|
+
host,
|
|
1391
|
+
engine,
|
|
1392
|
+
snapshot: snap,
|
|
1393
|
+
active: markupTool,
|
|
1394
|
+
onPick: setMarkupTool,
|
|
1395
|
+
blocked: dirty ? "Apply or discard the page changes first." : null,
|
|
1396
|
+
busy: markupBusy,
|
|
1397
|
+
online,
|
|
1398
|
+
error: markupError,
|
|
1399
|
+
onSave: () => void saveMarkup(),
|
|
1400
|
+
onDiscard: discardMarkup,
|
|
1401
|
+
onSoon: (id) => void announceSoon(id).catch(fail),
|
|
1402
|
+
goToPage,
|
|
1403
|
+
reloadKey
|
|
1404
|
+
}
|
|
1405
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
962
1406
|
ToolPanel,
|
|
963
1407
|
{
|
|
964
1408
|
tool: toolDef,
|
|
@@ -982,7 +1426,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
982
1426
|
}
|
|
983
1427
|
) })
|
|
984
1428
|
] });
|
|
985
|
-
const leftPanel = /* @__PURE__ */ (0,
|
|
1429
|
+
const leftPanel = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
986
1430
|
LeftPanel,
|
|
987
1431
|
{
|
|
988
1432
|
host,
|
|
@@ -1001,13 +1445,13 @@ function PdfWorkspace({ host, className }) {
|
|
|
1001
1445
|
}
|
|
1002
1446
|
);
|
|
1003
1447
|
const viewerPage = hostTool?.followsPage ? currentPage : 1;
|
|
1004
|
-
const viewer = (0,
|
|
1005
|
-
() => /* @__PURE__ */ (0,
|
|
1006
|
-
[host, reloadKey, zoom, spread, decisions.turns, viewerPage, onDocumentLoad, onPageSize]
|
|
1448
|
+
const viewer = (0, import_react4.useMemo)(
|
|
1449
|
+
() => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react4.Fragment, { children: host.renderViewer({ zoom, spread, rotations: decisions.turns, reloadKey, currentPage: viewerPage, onDocumentLoad, onPageSize, ...canMarkup ? { onMarkupEngine } : null }) }, reloadKey),
|
|
1450
|
+
[host, reloadKey, zoom, spread, decisions.turns, viewerPage, onDocumentLoad, onPageSize, canMarkup, onMarkupEngine]
|
|
1007
1451
|
);
|
|
1008
1452
|
const showChrome = !read;
|
|
1009
1453
|
const popCard = "absolute right-2 top-11 z-30 rounded-lg border border-border bg-popover p-3 text-popover-foreground shadow-lg";
|
|
1010
|
-
return /* @__PURE__ */ (0,
|
|
1454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1011
1455
|
"div",
|
|
1012
1456
|
{
|
|
1013
1457
|
ref: rootRef,
|
|
@@ -1015,18 +1459,18 @@ function PdfWorkspace({ host, className }) {
|
|
|
1015
1459
|
"data-pdf-workspace": "",
|
|
1016
1460
|
"data-compact": compact ? "" : void 0,
|
|
1017
1461
|
onKeyDown,
|
|
1018
|
-
className: (0,
|
|
1462
|
+
className: (0, import_cn2.cn)("relative flex h-full min-h-0 w-full flex-col overflow-hidden bg-background text-foreground outline-none", className),
|
|
1019
1463
|
children: [
|
|
1020
|
-
showChrome ? /* @__PURE__ */ (0,
|
|
1021
|
-
iconBtn("Page thumbnails", /* @__PURE__ */ (0,
|
|
1464
|
+
showChrome ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: BAR, "data-pdf-topbar": "", children: [
|
|
1465
|
+
iconBtn("Page thumbnails", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.PanelLeftIcon, {}), () => compact ? setSheet("pages") : setLeftOpen((v) => !v), { pressed: !compact && leftOpen }),
|
|
1022
1466
|
nameNode,
|
|
1023
1467
|
savePill,
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1025
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1026
|
-
/* @__PURE__ */ (0,
|
|
1027
|
-
|
|
1468
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-1" }),
|
|
1469
|
+
!compact ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-56", children: [
|
|
1470
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1471
|
+
import_controls5.Field,
|
|
1028
1472
|
{
|
|
1029
|
-
icon: /* @__PURE__ */ (0,
|
|
1473
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.SearchIcon, {}),
|
|
1030
1474
|
value: toolQuery,
|
|
1031
1475
|
"aria-label": "Search tools",
|
|
1032
1476
|
placeholder: "Search tools",
|
|
@@ -1044,7 +1488,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
1044
1488
|
}
|
|
1045
1489
|
}
|
|
1046
1490
|
),
|
|
1047
|
-
pop === "tool-search" && toolHits.length ? /* @__PURE__ */ (0,
|
|
1491
|
+
pop === "tool-search" && toolHits.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { role: "listbox", className: "absolute left-0 right-0 top-9 z-30 rounded-lg border border-border bg-popover p-1 shadow-lg", children: toolHits.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { role: "option", "aria-selected": false, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1048
1492
|
"button",
|
|
1049
1493
|
{
|
|
1050
1494
|
type: "button",
|
|
@@ -1056,25 +1500,25 @@ function PdfWorkspace({ host, className }) {
|
|
|
1056
1500
|
setPop(null);
|
|
1057
1501
|
},
|
|
1058
1502
|
children: [
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
t.status === "soon" ? /* @__PURE__ */ (0,
|
|
1503
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t.label }),
|
|
1504
|
+
t.status === "soon" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-muted-foreground", children: "Coming soon" }) : null
|
|
1061
1505
|
]
|
|
1062
1506
|
}
|
|
1063
1507
|
) }, t.id)) }) : null
|
|
1064
1508
|
] }) : null,
|
|
1065
|
-
iconBtn(
|
|
1066
|
-
iconBtn(
|
|
1067
|
-
!compact && iconBtn("Find", /* @__PURE__ */ (0,
|
|
1068
|
-
host.share && !compact ? iconBtn("Share", /* @__PURE__ */ (0,
|
|
1069
|
-
iconBtn("Download", /* @__PURE__ */ (0,
|
|
1070
|
-
host.print && !compact ? iconBtn("Print", /* @__PURE__ */ (0,
|
|
1071
|
-
!compact ? iconBtn("Keyboard shortcuts", /* @__PURE__ */ (0,
|
|
1072
|
-
compact ? /* @__PURE__ */ (0,
|
|
1509
|
+
iconBtn(undoText, /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.Undo2Icon, {}), () => runAction("undo"), { disabled: !canUndoAll }),
|
|
1510
|
+
iconBtn(redoText, /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.Undo2Icon, { className: "-scale-x-100" }), () => runAction("redo"), { disabled: !canRedoAll }),
|
|
1511
|
+
!compact && iconBtn("Find", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.SearchIcon, {}), () => runAction("find"), { pressed: findOpen }),
|
|
1512
|
+
host.share && !compact ? iconBtn("Share", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.Share2Icon, {}), () => host.share()) : null,
|
|
1513
|
+
iconBtn("Download", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.DownloadIcon, {}), () => host.download()),
|
|
1514
|
+
host.print && !compact ? iconBtn("Print", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.PrinterIcon, {}), () => setPop(pop === "print" ? null : "print"), { pressed: pop === "print" }) : null,
|
|
1515
|
+
!compact ? iconBtn("Keyboard shortcuts", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.KeyboardIcon, {}), () => runAction("shortcuts"), { pressed: pop === "shortcuts" }) : null,
|
|
1516
|
+
compact ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.Button, { variant: "outline", onClick: () => setSheet("tools"), children: "Tools" }) : iconBtn("Properties panel", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.PanelRightIcon, {}), () => setRightOpen((v) => !v), { pressed: rightOpen })
|
|
1073
1517
|
] }) : null,
|
|
1074
|
-
showChrome ? /* @__PURE__ */ (0,
|
|
1075
|
-
iconBtn("Previous page", /* @__PURE__ */ (0,
|
|
1076
|
-
/* @__PURE__ */ (0,
|
|
1077
|
-
|
|
1518
|
+
showChrome ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: BAR, "data-pdf-viewbar": "", children: [
|
|
1519
|
+
iconBtn("Previous page", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.ChevronLeftIcon, {}), () => goToPage(currentPage - 1), { disabled: currentPage <= 1 }),
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1521
|
+
import_controls5.Field,
|
|
1078
1522
|
{
|
|
1079
1523
|
type: "number",
|
|
1080
1524
|
min: 1,
|
|
@@ -1087,17 +1531,17 @@ function PdfWorkspace({ host, className }) {
|
|
|
1087
1531
|
className: compact ? "w-12" : "w-16"
|
|
1088
1532
|
}
|
|
1089
1533
|
),
|
|
1090
|
-
/* @__PURE__ */ (0,
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: [
|
|
1091
1535
|
"of ",
|
|
1092
1536
|
pageCount || "-"
|
|
1093
1537
|
] }),
|
|
1094
|
-
iconBtn("Next page", /* @__PURE__ */ (0,
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1096
|
-
iconBtn("Zoom out", /* @__PURE__ */ (0,
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1098
|
-
iconBtn("Zoom in", /* @__PURE__ */ (0,
|
|
1099
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1100
|
-
|
|
1538
|
+
iconBtn("Next page", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.ChevronRightIcon, {}), () => goToPage(currentPage + 1), { disabled: currentPage >= pageCount }),
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-1 h-5 w-px bg-border" }),
|
|
1540
|
+
iconBtn("Zoom out", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.MinusIcon, {}), () => stepZoom(-1)),
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: (0, import_cn2.cn)("min-w-[3rem] text-center text-xs tabular-nums", compact && "hidden"), "data-pdf-zoom": "", children: `${Math.round(zoom * 100)}%` }),
|
|
1542
|
+
iconBtn("Zoom in", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.PlusIcon, {}), () => stepZoom(1)),
|
|
1543
|
+
!compact ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1544
|
+
import_controls5.SegmentedControl,
|
|
1101
1545
|
{
|
|
1102
1546
|
value: zoomMode === "custom" ? null : zoomMode,
|
|
1103
1547
|
onValueChange: (v) => setZoomMode(v),
|
|
@@ -1105,39 +1549,40 @@ function PdfWorkspace({ host, className }) {
|
|
|
1105
1549
|
"aria-label": "Fit"
|
|
1106
1550
|
}
|
|
1107
1551
|
) : null,
|
|
1108
|
-
/* @__PURE__ */ (0,
|
|
1109
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1110
|
-
iconBtn("Rotate left", /* @__PURE__ */ (0,
|
|
1111
|
-
iconBtn("Rotate right", /* @__PURE__ */ (0,
|
|
1112
|
-
iconBtn("Delete page", /* @__PURE__ */ (0,
|
|
1113
|
-
/* @__PURE__ */ (0,
|
|
1114
|
-
iconBtn("Two pages side by side", /* @__PURE__ */ (0,
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-1" }),
|
|
1553
|
+
!compact ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1554
|
+
iconBtn("Rotate left", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.RotateCcwIcon, {}), () => turn(-90)),
|
|
1555
|
+
iconBtn("Rotate right", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.RotateCwIcon, {}), () => turn(90)),
|
|
1556
|
+
iconBtn("Delete page", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.Trash2Icon, {}), del, { disabled: decisions.order.length - decisions.deleted.length <= 1 }),
|
|
1557
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-1 h-5 w-px bg-border" }),
|
|
1558
|
+
iconBtn("Two pages side by side", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.Columns2Icon, {}), () => runAction("two-up"), { pressed: spread === "two-up" })
|
|
1115
1559
|
] }) : null,
|
|
1116
|
-
iconBtn("Reading mode", /* @__PURE__ */ (0,
|
|
1560
|
+
iconBtn("Reading mode", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.ExpandIcon, {}), () => setRead(true))
|
|
1117
1561
|
] }) : null,
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1119
|
-
showChrome && !compact ? /* @__PURE__ */ (0,
|
|
1120
|
-
showChrome && !compact && leftOpen ? /* @__PURE__ */ (0,
|
|
1121
|
-
/* @__PURE__ */ (0,
|
|
1122
|
-
findOpen ? /* @__PURE__ */ (0,
|
|
1123
|
-
/* @__PURE__ */ (0,
|
|
1124
|
-
|
|
1562
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative flex min-h-0 flex-1", children: [
|
|
1563
|
+
showChrome && !compact ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex w-10 shrink-0 flex-col items-center border-r border-border bg-background py-2", "data-pdf-rail": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.ToolRail, { groups: railGroups, value: pop === "all-tools" ? ALL_TOOLS : activeToolKey, onValueChange: (id) => id === ALL_TOOLS ? setPop((p) => p === "all-tools" ? null : "all-tools") : id && chooseTool(id), "aria-label": "PDF tools" }) }) : null,
|
|
1564
|
+
showChrome && !compact && leftOpen ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("aside", { className: "w-56 shrink-0 border-r border-border bg-background", "aria-label": "Pages", "data-pdf-left": "", children: leftPanel }) : null,
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("main", { className: "relative flex min-w-0 flex-1 flex-col", children: [
|
|
1566
|
+
findOpen ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute right-4 top-2 z-20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_RenderedFindBar.RenderedFindBar, { rootRef: scrollerRef, onClose: () => setFindOpen(false), label: "Find in document", focusRequest: findFocus, compact: true }) }) : null,
|
|
1567
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: scrollerRef, tabIndex: 0, "data-pdf-scroller": "", className: "min-h-0 flex-1 overflow-auto bg-muted outline-none", children: viewer }),
|
|
1568
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MarkupFloatingToolbar, { engine, snapshot: snap, enabled: markupOn && !read, onDone: () => scrollerRef.current?.focus({ preventScroll: true }) }),
|
|
1569
|
+
read ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute right-3 top-3 z-20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.XIcon, {}), onClick: () => setRead(false), children: "Exit reading mode" }) }) : null
|
|
1125
1570
|
] }),
|
|
1126
|
-
showChrome && !compact && rightOpen ? /* @__PURE__ */ (0,
|
|
1127
|
-
pop === "all-tools" ? /* @__PURE__ */ (0,
|
|
1571
|
+
showChrome && !compact && rightOpen ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("aside", { className: (0, import_cn2.cn)("shrink-0 border-l border-border bg-background", hostTool?.wide ? "w-[28rem]" : "w-72"), "aria-label": "Properties", "data-pdf-right": "", children: rightPanel }) : null,
|
|
1572
|
+
pop === "all-tools" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { role: "menu", "aria-label": "All tools", className: "absolute left-12 top-2 z-30 w-72 rounded-lg border border-border bg-popover p-1 shadow-lg", "data-pdf-all-tools": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolRows, { tool: activeToolKey, hostTools, canMarkup, onPick: (id) => {
|
|
1128
1573
|
setPop(null);
|
|
1129
1574
|
chooseTool(id);
|
|
1130
1575
|
} }) }) : null,
|
|
1131
|
-
pop === "print" && host.print ? /* @__PURE__ */ (0,
|
|
1132
|
-
/* @__PURE__ */ (0,
|
|
1133
|
-
printMode === "pages" ? /* @__PURE__ */ (0,
|
|
1134
|
-
/* @__PURE__ */ (0,
|
|
1135
|
-
|
|
1576
|
+
pop === "print" && host.print ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: (0, import_cn2.cn)(popCard, "w-72"), role: "dialog", "aria-label": "Print", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
1577
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.SegmentedControl, { fill: true, value: printMode, onValueChange: setPrintMode, data: [{ value: "all", label: "All pages" }, { value: "pages", label: "Pages" }], "aria-label": "What to print" }),
|
|
1578
|
+
printMode === "pages" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_controls5.PageRangeInput, { value: printRange, onChange: (t) => setPrintRange(t), pageCount }) : null,
|
|
1579
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1580
|
+
import_controls5.Button,
|
|
1136
1581
|
{
|
|
1137
1582
|
variant: "primary",
|
|
1138
|
-
disabled: busy || printMode === "pages" && !(0,
|
|
1583
|
+
disabled: busy || printMode === "pages" && !(0, import_controls5.parsePageRanges)(printRange, pageCount).valid,
|
|
1139
1584
|
onClick: () => {
|
|
1140
|
-
const pages = printMode === "pages" ? (0,
|
|
1585
|
+
const pages = printMode === "pages" ? (0, import_controls5.parsePageRanges)(printRange, pageCount).pages : null;
|
|
1141
1586
|
setBusy(true);
|
|
1142
1587
|
host.print(pages).then(() => setPop(null), fail).finally(() => setBusy(false));
|
|
1143
1588
|
},
|
|
@@ -1145,18 +1590,27 @@ function PdfWorkspace({ host, className }) {
|
|
|
1145
1590
|
}
|
|
1146
1591
|
)
|
|
1147
1592
|
] }) }) : null,
|
|
1148
|
-
pop === "shortcuts" ? /* @__PURE__ */ (0,
|
|
1149
|
-
/* @__PURE__ */ (0,
|
|
1150
|
-
|
|
1151
|
-
/* @__PURE__ */ (0,
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
/* @__PURE__ */ (0,
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1593
|
+
pop === "shortcuts" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: (0, import_cn2.cn)(popCard, "max-h-[70%] w-80 overflow-y-auto"), role: "dialog", "aria-label": "Keyboard shortcuts", "data-pdf-shortcuts": "", children: [
|
|
1594
|
+
["Edit", "View", "Pages", "Tools"].map((section) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mb-3 last:mb-0", children: [
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: section }),
|
|
1596
|
+
PDF_SHORTCUTS.filter((s) => s.section === section).map((s) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-between gap-2 py-0.5 text-xs", children: [
|
|
1597
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: s.label }),
|
|
1598
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("kbd", { className: "rounded border border-border px-1 text-muted-foreground", children: formatKeys(s.keys, isMac()) })
|
|
1599
|
+
] }, s.action))
|
|
1600
|
+
] }, section)),
|
|
1601
|
+
canMarkup ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mb-0", children: [
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "Markup" }),
|
|
1603
|
+
PDF_MARKUP_SHORTCUTS.filter((s) => s.tool !== "signature" || host.signaturePad).map((s) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex justify-between gap-2 py-0.5 text-xs", children: [
|
|
1604
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: s.label }),
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("kbd", { className: "rounded border border-border px-1 text-muted-foreground", children: s.keys })
|
|
1606
|
+
] }, s.tool))
|
|
1607
|
+
] }) : null
|
|
1608
|
+
] }) : null,
|
|
1609
|
+
compact && sheet ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1610
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "aria-label": "Close", className: "absolute inset-0 z-30 bg-background/60", onClick: () => setSheet(null) }),
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute inset-x-0 bottom-0 z-40 flex max-h-[75%] flex-col rounded-t-xl border-t border-border bg-background", role: "dialog", "aria-label": sheet === "pages" ? "Pages" : "Tools", children: sheet === "pages" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-[60vh] min-h-0", children: leftPanel }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-h-0 flex-col overflow-y-auto", children: [
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "p-2", role: "menu", "aria-label": "Tools", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolRows, { tool: activeToolKey, hostTools, canMarkup, onPick: chooseTool }) }),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-t border-border", children: rightPanel })
|
|
1160
1614
|
] }) })
|
|
1161
1615
|
] }) : null
|
|
1162
1616
|
] })
|