@ai-matrx/office 0.8.50 → 0.8.52
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 +29 -1
- package/dist/pdf-model.cjs +117 -3
- package/dist/pdf-model.cjs.map +1 -1
- package/dist/pdf-model.d.cts +171 -3
- package/dist/pdf-model.d.ts +171 -3
- package/dist/pdf-model.js +117 -3
- package/dist/pdf-model.js.map +1 -1
- package/dist/pdf.cjs +643 -190
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +171 -3
- package/dist/pdf.d.ts +171 -3
- package/dist/pdf.js +620 -154
- package/dist/pdf.js.map +1 -1
- package/package.json +7 -5
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
|
|
@@ -430,9 +450,94 @@ var canRedo = (h) => h.future.length > 0;
|
|
|
430
450
|
var undoLabel = (h) => h.present.label;
|
|
431
451
|
var redoLabel = (h) => h.future[0]?.label ?? "";
|
|
432
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
|
+
|
|
433
537
|
// src/pdf/tools.ts
|
|
434
538
|
var PDF_TOOLS = [
|
|
435
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." },
|
|
436
541
|
{ id: "organize", label: "Organize pages", key: "o", status: "ready", capability: "rotate-pages,delete-pages,reorder-pages", opens: "panel", group: 0 },
|
|
437
542
|
{ id: "extract-pages", label: "Extract pages", key: "e", status: "ready", capability: "extract-pages", opens: "panel", group: 0 },
|
|
438
543
|
{ id: "split", label: "Split", key: "s", status: "ready", capability: "split", opens: "panel", group: 0 },
|
|
@@ -453,7 +558,7 @@ var PDF_TOOLS = [
|
|
|
453
558
|
var pdfTool = (id) => PDF_TOOLS.find((t) => t.id === id);
|
|
454
559
|
var comingSoonIdOf = (id) => `pdf.${id}`;
|
|
455
560
|
var PROMISES = {
|
|
456
|
-
edit: "Change text and swap images
|
|
561
|
+
edit: "Change the page's own text and swap images, with a before-and-after view.",
|
|
457
562
|
forms: "Fill in a form and keep the values in the file.",
|
|
458
563
|
protect: "Lock a PDF with a password and limit what others can do.",
|
|
459
564
|
ocr: "Turn a scanned PDF into one you can search and copy from.",
|
|
@@ -478,14 +583,15 @@ var PDF_COMING_SOON = {
|
|
|
478
583
|
return [id, { id, label: t.label, owner: "pdf", promise: PROMISES[t.id] ?? "", stage: "planned", surfaces: ["PDF workspace tool rail"] }];
|
|
479
584
|
})
|
|
480
585
|
),
|
|
481
|
-
...PANEL_PROMISES
|
|
586
|
+
...PANEL_PROMISES,
|
|
587
|
+
...PDF_MARKUP_COMING_SOON
|
|
482
588
|
};
|
|
483
589
|
|
|
484
590
|
// src/pdf/shortcuts.ts
|
|
485
591
|
var PDF_SHORTCUTS = [
|
|
486
592
|
{ action: "undo", label: "Undo", keys: "Mod+Z", section: "Edit" },
|
|
487
593
|
{ action: "redo", label: "Redo", keys: "Mod+Shift+Z", section: "Edit" },
|
|
488
|
-
{ action: "save", label: "
|
|
594
|
+
{ action: "save", label: "Save markup or apply page changes", keys: "Mod+S", section: "Edit" },
|
|
489
595
|
{ action: "find", label: "Find", keys: "Mod+F", section: "Edit" },
|
|
490
596
|
{ action: "print", label: "Print", keys: "Mod+P", section: "Edit" },
|
|
491
597
|
{ action: "zoom-in", label: "Zoom in", keys: "Mod+=", section: "View" },
|
|
@@ -512,6 +618,14 @@ var PDF_SHORTCUTS = [
|
|
|
512
618
|
section: "Tools"
|
|
513
619
|
}))
|
|
514
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
|
+
}
|
|
515
629
|
function parse(keys) {
|
|
516
630
|
const parts = keys.split("+");
|
|
517
631
|
const key = parts[parts.length - 1] === "" ? "+" : parts[parts.length - 1];
|
|
@@ -538,30 +652,222 @@ function formatKeys(keys, mac) {
|
|
|
538
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 ? "" : "+");
|
|
539
653
|
}
|
|
540
654
|
|
|
541
|
-
// 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");
|
|
542
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");
|
|
543
848
|
var PDF_TOOL_ICONS = {
|
|
544
|
-
browse:
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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
|
|
561
867
|
};
|
|
562
868
|
|
|
563
869
|
// src/pdf/PdfWorkspace.tsx
|
|
564
|
-
var
|
|
870
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
565
871
|
var ZOOM_STEPS = [0.5, 0.75, 1, 1.25, 1.5, 2, 3];
|
|
566
872
|
var COMPACT_BELOW_PX = 768;
|
|
567
873
|
var BAR = "flex h-10 shrink-0 items-center gap-1 border-b border-border bg-background px-2";
|
|
@@ -573,8 +879,8 @@ async function announceSoon(id) {
|
|
|
573
879
|
await announceComingSoon(id);
|
|
574
880
|
}
|
|
575
881
|
function useWidth(ref) {
|
|
576
|
-
const [size, setSize] = (0,
|
|
577
|
-
(0,
|
|
882
|
+
const [size, setSize] = (0, import_react4.useState)({ w: 1200, h: 800 });
|
|
883
|
+
(0, import_react4.useLayoutEffect)(() => {
|
|
578
884
|
const node = ref.current;
|
|
579
885
|
if (!node) return void 0;
|
|
580
886
|
const measure = () => setSize({ w: node.clientWidth || 1200, h: node.clientHeight || 800 });
|
|
@@ -586,36 +892,36 @@ function useWidth(ref) {
|
|
|
586
892
|
}, [ref]);
|
|
587
893
|
return size;
|
|
588
894
|
}
|
|
589
|
-
function ToolRows({ tool, hostTools, onPick }) {
|
|
590
|
-
return /* @__PURE__ */ (0,
|
|
591
|
-
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)(
|
|
592
898
|
"button",
|
|
593
899
|
{
|
|
594
900
|
type: "button",
|
|
595
901
|
role: "menuitem",
|
|
596
902
|
"aria-current": tool === `host:${t.id}` ? "true" : void 0,
|
|
597
|
-
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"),
|
|
598
904
|
onClick: () => onPick(`host:${t.id}`),
|
|
599
905
|
children: [
|
|
600
|
-
/* @__PURE__ */ (0,
|
|
601
|
-
/* @__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 })
|
|
602
908
|
]
|
|
603
909
|
}
|
|
604
910
|
) }, `host:${t.id}`)),
|
|
605
|
-
PDF_TOOLS.filter((t) => t.id !== "browse").map((t) => {
|
|
911
|
+
PDF_TOOLS.filter((t) => t.id !== "browse" && (t.id !== "markup" || canMarkup)).map((t) => {
|
|
606
912
|
const Icon = PDF_TOOL_ICONS[t.id];
|
|
607
|
-
return /* @__PURE__ */ (0,
|
|
913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
608
914
|
"button",
|
|
609
915
|
{
|
|
610
916
|
type: "button",
|
|
611
917
|
role: "menuitem",
|
|
612
918
|
"aria-current": t.id === tool ? "true" : void 0,
|
|
613
|
-
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"),
|
|
614
920
|
onClick: () => onPick(t.id),
|
|
615
921
|
children: [
|
|
616
|
-
/* @__PURE__ */ (0,
|
|
617
|
-
/* @__PURE__ */ (0,
|
|
618
|
-
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
|
|
619
925
|
]
|
|
620
926
|
}
|
|
621
927
|
) }, t.id);
|
|
@@ -623,50 +929,58 @@ function ToolRows({ tool, hostTools, onPick }) {
|
|
|
623
929
|
] });
|
|
624
930
|
}
|
|
625
931
|
function PdfWorkspace({ host, className }) {
|
|
626
|
-
const rootRef = (0,
|
|
627
|
-
const scrollerRef = (0,
|
|
932
|
+
const rootRef = (0, import_react4.useRef)(null);
|
|
933
|
+
const scrollerRef = (0, import_react4.useRef)(null);
|
|
628
934
|
const rootSize = useWidth(rootRef);
|
|
629
935
|
const viewSize = useWidth(scrollerRef);
|
|
630
936
|
const compact = rootSize.w < COMPACT_BELOW_PX;
|
|
631
937
|
const online = host.online !== false;
|
|
632
|
-
const [pageCount, setPageCount] = (0,
|
|
633
|
-
const [history, setHistory] = (0,
|
|
938
|
+
const [pageCount, setPageCount] = (0, import_react4.useState)(0);
|
|
939
|
+
const [history, setHistory] = (0, import_react4.useState)(() => startHistory(freshDecisions(0)));
|
|
634
940
|
const decisions = history.present.value;
|
|
635
941
|
const dirty = isDirty(decisions);
|
|
636
|
-
const [tool, setTool] = (0,
|
|
637
|
-
const [hostToolId, setHostToolId] = (0,
|
|
638
|
-
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]);
|
|
639
945
|
const hostTool = hostToolId ? hostTools.find((t) => t.id === hostToolId) ?? null : null;
|
|
640
946
|
const activeToolKey = hostTool ? `host:${hostTool.id}` : tool;
|
|
641
|
-
const [leftOpen, setLeftOpen] = (0,
|
|
642
|
-
const [rightOpen, setRightOpen] = (0,
|
|
643
|
-
const [leftTab, setLeftTab] = (0,
|
|
644
|
-
const [read, setRead] = (0,
|
|
645
|
-
const [spread, setSpread] = (0,
|
|
646
|
-
const [zoomMode, setZoomMode] = (0,
|
|
647
|
-
const [customZoom, setCustomZoom] = (0,
|
|
648
|
-
const [selected, setSelected] = (0,
|
|
649
|
-
const [currentPage, setCurrentPage] = (0,
|
|
650
|
-
const [pageDraft, setPageDraft] = (0,
|
|
651
|
-
const [findOpen, setFindOpen] = (0,
|
|
652
|
-
const [findFocus, setFindFocus] = (0,
|
|
653
|
-
const [pop, setPop] = (0,
|
|
654
|
-
const [sheet, setSheet] = (0,
|
|
655
|
-
const [toolQuery, setToolQuery] = (0,
|
|
656
|
-
const [busy, setBusy] = (0,
|
|
657
|
-
const [error, setError] = (0,
|
|
658
|
-
const [result, setResult] = (0,
|
|
659
|
-
const [reloadKey, setReloadKey] = (0,
|
|
660
|
-
const [sizeVersion, setSizeVersion] = (0,
|
|
661
|
-
const sizes = (0,
|
|
662
|
-
const [editingName, setEditingName] = (0,
|
|
663
|
-
const [nameDraft, setNameDraft] = (0,
|
|
664
|
-
const [printMode, setPrintMode] = (0,
|
|
665
|
-
const [printRange, setPrintRange] = (0,
|
|
666
|
-
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]);
|
|
667
981
|
const toolDef = pdfTool(tool);
|
|
668
982
|
const first = sizes.current.get(1);
|
|
669
|
-
const fitPage = (0,
|
|
983
|
+
const fitPage = (0, import_react4.useMemo)(() => {
|
|
670
984
|
void sizeVersion;
|
|
671
985
|
if (!first) return 1;
|
|
672
986
|
const ratio = first.h / first.w;
|
|
@@ -675,7 +989,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
675
989
|
return clampZoom(availH * cols / (Math.max(1, viewSize.w) * ratio));
|
|
676
990
|
}, [first, spread, viewSize.h, viewSize.w, sizeVersion]);
|
|
677
991
|
const zoom = zoomMode === "fit-width" ? 1 : zoomMode === "fit-page" ? fitPage : customZoom;
|
|
678
|
-
const stepZoom = (0,
|
|
992
|
+
const stepZoom = (0, import_react4.useCallback)(
|
|
679
993
|
(dir) => {
|
|
680
994
|
const cur = zoomMode === "fit-width" ? 1 : zoomMode === "fit-page" ? fitPage : customZoom;
|
|
681
995
|
const next = dir > 0 ? ZOOM_STEPS.find((s) => s > cur + 0.01) : [...ZOOM_STEPS].reverse().find((s) => s < cur - 0.01);
|
|
@@ -685,7 +999,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
685
999
|
},
|
|
686
1000
|
[zoomMode, fitPage, customZoom]
|
|
687
1001
|
);
|
|
688
|
-
const goToPage = (0,
|
|
1002
|
+
const goToPage = (0, import_react4.useCallback)(
|
|
689
1003
|
(n) => {
|
|
690
1004
|
const page = Math.min(Math.max(1, Math.round(n)), Math.max(1, pageCount));
|
|
691
1005
|
setCurrentPage(page);
|
|
@@ -695,7 +1009,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
695
1009
|
},
|
|
696
1010
|
[pageCount]
|
|
697
1011
|
);
|
|
698
|
-
(0,
|
|
1012
|
+
(0, import_react4.useEffect)(() => {
|
|
699
1013
|
const node = scrollerRef.current;
|
|
700
1014
|
if (!node) return void 0;
|
|
701
1015
|
let raf = 0;
|
|
@@ -722,34 +1036,37 @@ function PdfWorkspace({ host, className }) {
|
|
|
722
1036
|
cancelAnimationFrame(raf);
|
|
723
1037
|
};
|
|
724
1038
|
}, [pageCount]);
|
|
725
|
-
const commit = (0,
|
|
726
|
-
|
|
727
|
-
|
|
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)(
|
|
728
1045
|
(by) => {
|
|
729
1046
|
const t = targets();
|
|
730
1047
|
commit(`Rotate ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, turnPages(decisions, t, by));
|
|
731
1048
|
},
|
|
732
1049
|
[targets, commit, decisions]
|
|
733
1050
|
);
|
|
734
|
-
const del = (0,
|
|
1051
|
+
const del = (0, import_react4.useCallback)(() => {
|
|
735
1052
|
const t = targets();
|
|
736
1053
|
commit(`Delete ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, deletePages(decisions, t));
|
|
737
1054
|
}, [targets, commit, decisions]);
|
|
738
|
-
const restore = (0,
|
|
1055
|
+
const restore = (0, import_react4.useCallback)(() => {
|
|
739
1056
|
const t = targets();
|
|
740
1057
|
commit(`Restore ${t.length === 1 ? `page ${t[0]}` : `${t.length} pages`}`, restorePages(decisions, t));
|
|
741
1058
|
}, [targets, commit, decisions]);
|
|
742
|
-
const onDocumentLoad = (0,
|
|
1059
|
+
const onDocumentLoad = (0, import_react4.useCallback)((n) => {
|
|
743
1060
|
setPageCount(n);
|
|
744
1061
|
setHistory((h) => h.present.value.order.length === n ? h : startHistory(freshDecisions(n)));
|
|
745
1062
|
}, []);
|
|
746
|
-
const onPageSize = (0,
|
|
1063
|
+
const onPageSize = (0, import_react4.useCallback)((page, w, h) => {
|
|
747
1064
|
const prev = sizes.current.get(page);
|
|
748
1065
|
if (prev && prev.w === w && prev.h === h) return;
|
|
749
1066
|
sizes.current.set(page, { w, h });
|
|
750
1067
|
if (page === 1) queueMicrotask(() => setSizeVersion((v) => v + 1));
|
|
751
1068
|
}, []);
|
|
752
|
-
const fail = (0,
|
|
1069
|
+
const fail = (0, import_react4.useCallback)(
|
|
753
1070
|
(e) => {
|
|
754
1071
|
const message = e instanceof Error ? e.message : "That did not work.";
|
|
755
1072
|
setError(message);
|
|
@@ -757,7 +1074,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
757
1074
|
},
|
|
758
1075
|
[host]
|
|
759
1076
|
);
|
|
760
|
-
const runTool = (0,
|
|
1077
|
+
const runTool = (0, import_react4.useCallback)(
|
|
761
1078
|
async (request) => {
|
|
762
1079
|
if (!online) {
|
|
763
1080
|
setError("You are offline. Changes are not queued; try again when you are back online.");
|
|
@@ -783,12 +1100,109 @@ function PdfWorkspace({ host, className }) {
|
|
|
783
1100
|
},
|
|
784
1101
|
[host, online, pageCount, fail]
|
|
785
1102
|
);
|
|
786
|
-
const apply = (0,
|
|
1103
|
+
const apply = (0, import_react4.useCallback)(() => {
|
|
787
1104
|
const ops = compilePageOps(decisions);
|
|
788
|
-
if (ops.length)
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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)(
|
|
792
1206
|
(id) => {
|
|
793
1207
|
if (id.startsWith("host:")) {
|
|
794
1208
|
setHostToolId(id.slice(5));
|
|
@@ -799,7 +1213,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
799
1213
|
return;
|
|
800
1214
|
}
|
|
801
1215
|
const def = pdfTool(id);
|
|
802
|
-
if (!def) return;
|
|
1216
|
+
if (!def || def.id === "markup" && !host.saveMarkup) return;
|
|
803
1217
|
setHostToolId(null);
|
|
804
1218
|
if (def.status === "soon") {
|
|
805
1219
|
announceSoon(comingSoonIdOf(def.id)).catch(fail);
|
|
@@ -817,26 +1231,26 @@ function PdfWorkspace({ host, className }) {
|
|
|
817
1231
|
},
|
|
818
1232
|
[host, compact, fail]
|
|
819
1233
|
);
|
|
820
|
-
const railGroups = (0,
|
|
1234
|
+
const railGroups = (0, import_react4.useMemo)(() => {
|
|
821
1235
|
const groups = [[], [], []];
|
|
822
1236
|
for (const t of PDF_TOOLS) {
|
|
823
|
-
if (t.status !== "ready") continue;
|
|
1237
|
+
if (t.status !== "ready" || t.id === "markup" && !canMarkup) continue;
|
|
824
1238
|
groups[t.group].push({ id: t.id, label: t.label, icon: PDF_TOOL_ICONS[t.id], ...t.key ? { shortcut: t.key.toUpperCase() } : null });
|
|
825
1239
|
}
|
|
826
1240
|
for (const t of hostTools) groups[t.group ?? 1].push({ id: `host:${t.id}`, label: t.label, icon: t.icon });
|
|
827
|
-
groups[2].push({ id: ALL_TOOLS, label: "All tools", icon:
|
|
1241
|
+
groups[2].push({ id: ALL_TOOLS, label: "All tools", icon: import_icons3.MoreHorizontalIcon });
|
|
828
1242
|
return groups.filter((g) => g.length);
|
|
829
|
-
}, [hostTools]);
|
|
830
|
-
const runAction = (0,
|
|
1243
|
+
}, [hostTools, canMarkup]);
|
|
1244
|
+
const runAction = (0, import_react4.useCallback)(
|
|
831
1245
|
(action) => {
|
|
832
1246
|
if (action.startsWith("tool:")) return chooseTool(action.slice(5));
|
|
833
1247
|
switch (action) {
|
|
834
1248
|
case "undo":
|
|
835
|
-
return
|
|
1249
|
+
return undoAll();
|
|
836
1250
|
case "redo":
|
|
837
|
-
return
|
|
1251
|
+
return redoAll();
|
|
838
1252
|
case "save":
|
|
839
|
-
return apply();
|
|
1253
|
+
return markupPending ? void saveMarkup() : apply();
|
|
840
1254
|
case "find":
|
|
841
1255
|
setFindOpen(true);
|
|
842
1256
|
setFindFocus((n) => n + 1);
|
|
@@ -881,7 +1295,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
881
1295
|
return void 0;
|
|
882
1296
|
}
|
|
883
1297
|
},
|
|
884
|
-
[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]
|
|
885
1299
|
);
|
|
886
1300
|
const onKeyDown = (e) => {
|
|
887
1301
|
const t = e.target;
|
|
@@ -893,19 +1307,30 @@ function PdfWorkspace({ host, className }) {
|
|
|
893
1307
|
else if (sheet) setSheet(null);
|
|
894
1308
|
return;
|
|
895
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
|
+
}
|
|
896
1318
|
const action = matchShortcut(e.nativeEvent, typing);
|
|
897
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;
|
|
898
1321
|
if ((action === "page-next" || action === "page-prev") && t !== scrollerRef.current && t !== rootRef.current) return;
|
|
899
1322
|
if (action === "delete-pages" && t.closest("[data-pdf-thumbnails]") === null && t !== scrollerRef.current) return;
|
|
900
1323
|
e.preventDefault();
|
|
1324
|
+
if (action === "undo" || action === "redo") e.stopPropagation();
|
|
901
1325
|
runAction(action);
|
|
902
1326
|
};
|
|
903
|
-
const
|
|
904
|
-
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)(
|
|
905
1330
|
"span",
|
|
906
1331
|
{
|
|
907
1332
|
role: "status",
|
|
908
|
-
className: (0,
|
|
1333
|
+
className: (0, import_cn2.cn)(
|
|
909
1334
|
"inline-flex h-6 shrink-0 items-center justify-center whitespace-nowrap rounded-full border px-2 text-xs",
|
|
910
1335
|
saveState === "Unsaved" || saveState === "Offline" || saveState === "Not saved" ? "border-border text-foreground" : "border-border text-muted-foreground",
|
|
911
1336
|
busy && "animate-pulse"
|
|
@@ -913,13 +1338,13 @@ function PdfWorkspace({ host, className }) {
|
|
|
913
1338
|
children: saveState
|
|
914
1339
|
}
|
|
915
1340
|
);
|
|
916
|
-
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 });
|
|
917
1342
|
const toolHits = toolQuery.trim() ? [
|
|
918
1343
|
...hostTools.map((t) => ({ id: `host:${t.id}`, label: t.label, status: "ready" })),
|
|
919
1344
|
...PDF_TOOLS
|
|
920
1345
|
].filter((t) => t.label.toLowerCase().includes(toolQuery.trim().toLowerCase())) : [];
|
|
921
|
-
const nameNode = editingName && host.rename ? /* @__PURE__ */ (0,
|
|
922
|
-
|
|
1346
|
+
const nameNode = editingName && host.rename ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1347
|
+
import_controls5.Field,
|
|
923
1348
|
{
|
|
924
1349
|
autoFocus: true,
|
|
925
1350
|
value: nameDraft,
|
|
@@ -938,7 +1363,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
938
1363
|
},
|
|
939
1364
|
width: "lg"
|
|
940
1365
|
}
|
|
941
|
-
) : /* @__PURE__ */ (0,
|
|
1366
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
942
1367
|
"button",
|
|
943
1368
|
{
|
|
944
1369
|
type: "button",
|
|
@@ -948,18 +1373,36 @@ function PdfWorkspace({ host, className }) {
|
|
|
948
1373
|
children: host.file.name
|
|
949
1374
|
}
|
|
950
1375
|
);
|
|
951
|
-
const rightPanel = hostTool ? /* @__PURE__ */ (0,
|
|
952
|
-
/* @__PURE__ */ (0,
|
|
953
|
-
/* @__PURE__ */ (0,
|
|
954
|
-
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
|
|
955
1380
|
] }),
|
|
956
|
-
/* @__PURE__ */ (0,
|
|
957
|
-
] }) : /* @__PURE__ */ (0,
|
|
958
|
-
/* @__PURE__ */ (0,
|
|
959
|
-
/* @__PURE__ */ (0,
|
|
960
|
-
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
|
|
961
1386
|
] }),
|
|
962
|
-
/* @__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)(
|
|
963
1406
|
ToolPanel,
|
|
964
1407
|
{
|
|
965
1408
|
tool: toolDef,
|
|
@@ -983,7 +1426,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
983
1426
|
}
|
|
984
1427
|
) })
|
|
985
1428
|
] });
|
|
986
|
-
const leftPanel = /* @__PURE__ */ (0,
|
|
1429
|
+
const leftPanel = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
987
1430
|
LeftPanel,
|
|
988
1431
|
{
|
|
989
1432
|
host,
|
|
@@ -1002,13 +1445,13 @@ function PdfWorkspace({ host, className }) {
|
|
|
1002
1445
|
}
|
|
1003
1446
|
);
|
|
1004
1447
|
const viewerPage = hostTool?.followsPage ? currentPage : 1;
|
|
1005
|
-
const viewer = (0,
|
|
1006
|
-
() => /* @__PURE__ */ (0,
|
|
1007
|
-
[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]
|
|
1008
1451
|
);
|
|
1009
1452
|
const showChrome = !read;
|
|
1010
1453
|
const popCard = "absolute right-2 top-11 z-30 rounded-lg border border-border bg-popover p-3 text-popover-foreground shadow-lg";
|
|
1011
|
-
return /* @__PURE__ */ (0,
|
|
1454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1012
1455
|
"div",
|
|
1013
1456
|
{
|
|
1014
1457
|
ref: rootRef,
|
|
@@ -1016,18 +1459,18 @@ function PdfWorkspace({ host, className }) {
|
|
|
1016
1459
|
"data-pdf-workspace": "",
|
|
1017
1460
|
"data-compact": compact ? "" : void 0,
|
|
1018
1461
|
onKeyDown,
|
|
1019
|
-
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),
|
|
1020
1463
|
children: [
|
|
1021
|
-
showChrome ? /* @__PURE__ */ (0,
|
|
1022
|
-
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 }),
|
|
1023
1466
|
nameNode,
|
|
1024
1467
|
savePill,
|
|
1025
|
-
/* @__PURE__ */ (0,
|
|
1026
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1027
|
-
/* @__PURE__ */ (0,
|
|
1028
|
-
|
|
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,
|
|
1029
1472
|
{
|
|
1030
|
-
icon: /* @__PURE__ */ (0,
|
|
1473
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.SearchIcon, {}),
|
|
1031
1474
|
value: toolQuery,
|
|
1032
1475
|
"aria-label": "Search tools",
|
|
1033
1476
|
placeholder: "Search tools",
|
|
@@ -1045,7 +1488,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
1045
1488
|
}
|
|
1046
1489
|
}
|
|
1047
1490
|
),
|
|
1048
|
-
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)(
|
|
1049
1492
|
"button",
|
|
1050
1493
|
{
|
|
1051
1494
|
type: "button",
|
|
@@ -1057,25 +1500,25 @@ function PdfWorkspace({ host, className }) {
|
|
|
1057
1500
|
setPop(null);
|
|
1058
1501
|
},
|
|
1059
1502
|
children: [
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1061
|
-
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
|
|
1062
1505
|
]
|
|
1063
1506
|
}
|
|
1064
1507
|
) }, t.id)) }) : null
|
|
1065
1508
|
] }) : null,
|
|
1066
|
-
iconBtn(
|
|
1067
|
-
iconBtn(
|
|
1068
|
-
!compact && iconBtn("Find", /* @__PURE__ */ (0,
|
|
1069
|
-
host.share && !compact ? iconBtn("Share", /* @__PURE__ */ (0,
|
|
1070
|
-
iconBtn("Download", /* @__PURE__ */ (0,
|
|
1071
|
-
host.print && !compact ? iconBtn("Print", /* @__PURE__ */ (0,
|
|
1072
|
-
!compact ? iconBtn("Keyboard shortcuts", /* @__PURE__ */ (0,
|
|
1073
|
-
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 })
|
|
1074
1517
|
] }) : null,
|
|
1075
|
-
showChrome ? /* @__PURE__ */ (0,
|
|
1076
|
-
iconBtn("Previous page", /* @__PURE__ */ (0,
|
|
1077
|
-
/* @__PURE__ */ (0,
|
|
1078
|
-
|
|
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,
|
|
1079
1522
|
{
|
|
1080
1523
|
type: "number",
|
|
1081
1524
|
min: 1,
|
|
@@ -1088,17 +1531,17 @@ function PdfWorkspace({ host, className }) {
|
|
|
1088
1531
|
className: compact ? "w-12" : "w-16"
|
|
1089
1532
|
}
|
|
1090
1533
|
),
|
|
1091
|
-
/* @__PURE__ */ (0,
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: [
|
|
1092
1535
|
"of ",
|
|
1093
1536
|
pageCount || "-"
|
|
1094
1537
|
] }),
|
|
1095
|
-
iconBtn("Next page", /* @__PURE__ */ (0,
|
|
1096
|
-
/* @__PURE__ */ (0,
|
|
1097
|
-
iconBtn("Zoom out", /* @__PURE__ */ (0,
|
|
1098
|
-
/* @__PURE__ */ (0,
|
|
1099
|
-
iconBtn("Zoom in", /* @__PURE__ */ (0,
|
|
1100
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1101
|
-
|
|
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,
|
|
1102
1545
|
{
|
|
1103
1546
|
value: zoomMode === "custom" ? null : zoomMode,
|
|
1104
1547
|
onValueChange: (v) => setZoomMode(v),
|
|
@@ -1106,39 +1549,40 @@ function PdfWorkspace({ host, className }) {
|
|
|
1106
1549
|
"aria-label": "Fit"
|
|
1107
1550
|
}
|
|
1108
1551
|
) : null,
|
|
1109
|
-
/* @__PURE__ */ (0,
|
|
1110
|
-
!compact ? /* @__PURE__ */ (0,
|
|
1111
|
-
iconBtn("Rotate left", /* @__PURE__ */ (0,
|
|
1112
|
-
iconBtn("Rotate right", /* @__PURE__ */ (0,
|
|
1113
|
-
iconBtn("Delete page", /* @__PURE__ */ (0,
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1115
|
-
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" })
|
|
1116
1559
|
] }) : null,
|
|
1117
|
-
iconBtn("Reading mode", /* @__PURE__ */ (0,
|
|
1560
|
+
iconBtn("Reading mode", /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons3.ExpandIcon, {}), () => setRead(true))
|
|
1118
1561
|
] }) : null,
|
|
1119
|
-
/* @__PURE__ */ (0,
|
|
1120
|
-
showChrome && !compact ? /* @__PURE__ */ (0,
|
|
1121
|
-
showChrome && !compact && leftOpen ? /* @__PURE__ */ (0,
|
|
1122
|
-
/* @__PURE__ */ (0,
|
|
1123
|
-
findOpen ? /* @__PURE__ */ (0,
|
|
1124
|
-
/* @__PURE__ */ (0,
|
|
1125
|
-
|
|
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
|
|
1126
1570
|
] }),
|
|
1127
|
-
showChrome && !compact && rightOpen ? /* @__PURE__ */ (0,
|
|
1128
|
-
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) => {
|
|
1129
1573
|
setPop(null);
|
|
1130
1574
|
chooseTool(id);
|
|
1131
1575
|
} }) }) : null,
|
|
1132
|
-
pop === "print" && host.print ? /* @__PURE__ */ (0,
|
|
1133
|
-
/* @__PURE__ */ (0,
|
|
1134
|
-
printMode === "pages" ? /* @__PURE__ */ (0,
|
|
1135
|
-
/* @__PURE__ */ (0,
|
|
1136
|
-
|
|
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,
|
|
1137
1581
|
{
|
|
1138
1582
|
variant: "primary",
|
|
1139
|
-
disabled: busy || printMode === "pages" && !(0,
|
|
1583
|
+
disabled: busy || printMode === "pages" && !(0, import_controls5.parsePageRanges)(printRange, pageCount).valid,
|
|
1140
1584
|
onClick: () => {
|
|
1141
|
-
const pages = printMode === "pages" ? (0,
|
|
1585
|
+
const pages = printMode === "pages" ? (0, import_controls5.parsePageRanges)(printRange, pageCount).pages : null;
|
|
1142
1586
|
setBusy(true);
|
|
1143
1587
|
host.print(pages).then(() => setPop(null), fail).finally(() => setBusy(false));
|
|
1144
1588
|
},
|
|
@@ -1146,18 +1590,27 @@ function PdfWorkspace({ host, className }) {
|
|
|
1146
1590
|
}
|
|
1147
1591
|
)
|
|
1148
1592
|
] }) }) : null,
|
|
1149
|
-
pop === "shortcuts" ? /* @__PURE__ */ (0,
|
|
1150
|
-
/* @__PURE__ */ (0,
|
|
1151
|
-
|
|
1152
|
-
/* @__PURE__ */ (0,
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
/* @__PURE__ */ (0,
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
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 })
|
|
1161
1614
|
] }) })
|
|
1162
1615
|
] }) : null
|
|
1163
1616
|
] })
|