@ai-matrx/office 0.8.48 → 0.8.50
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 +17 -1
- package/dist/pdf-model.d.cts +40 -2
- package/dist/pdf-model.d.ts +40 -2
- package/dist/pdf.cjs +62 -21
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +40 -2
- package/dist/pdf.d.ts +40 -2
- package/dist/pdf.js +62 -21
- package/dist/pdf.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.8.
|
|
3
|
+
## 0.8.50
|
|
4
4
|
|
|
5
5
|
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
6
6
|
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/office/src`.
|
|
7
7
|
|
|
8
|
+
## 0.8.49
|
|
9
|
+
|
|
10
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
11
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
12
|
+
Diff: `git diff 184cfc8959 90e2be3bbc -- apps/shared/office/src`
|
|
13
|
+
|
|
14
|
+
Changed shipped source files (2):
|
|
15
|
+
- `apps/shared/office/src/pdf/PdfWorkspace.tsx`
|
|
16
|
+
- `apps/shared/office/src/pdf/ports.ts`
|
|
17
|
+
|
|
18
|
+
## 0.8.48
|
|
19
|
+
|
|
20
|
+
Automatic changed-only republish (docs/metadata drift since the last published version; verified: `git diff 5da59424ae 184cfc8959 -- apps/shared/office/src`
|
|
21
|
+
has no shipped-source changes outside tests, fixtures and docs). No consumer action required.
|
|
22
|
+
|
|
8
23
|
## 0.8.47
|
|
9
24
|
|
|
10
25
|
- `EditorBridgeLike` / `FilterServiceLike` accept Univer's own `IEditorBridgeService` and `SheetsFilterService` types (their `Nullable<…>` returns, `IRange`): a host passing `injector.get(IEditorBridgeService)` to `editorBridgeCell`, or the filter service to `filterServiceRange`, type-checks. New `FilterRangeLike`. Consumer action: none.
|
|
@@ -305,6 +320,7 @@ Changed shipped source files (8):
|
|
|
305
320
|
|
|
306
321
|
### Unreleased
|
|
307
322
|
|
|
323
|
+
- `./pdf`: `PdfWorkspaceHost.tools` lets the host bring its own rail tools (`PdfHostTool`: id, label, icon, `render(context)`, optional `wide` and `followsPage`); the shell gives each a rail button, an All-tools row, tool-search hit and the right panel, and tells it the page, page count, selection, `goToPage` and `reload`. `PdfViewerState.currentPage` is passed while a `followsPage` tool is open. Consumer action: none (optional).
|
|
308
324
|
- **US spelling: the British spelling of "color" no longer exists in this package (Arman, 2026-10-21).** Every label, template string, comment, identifier, CSS class/variable and test name that spelled it the British way now says color. Guard: `design-system/src/us-spelling.test.ts` scans all of `apps/` for the word. Consumer action: none for imports; if you matched on a British-spelled identifier, class or CSS variable from this package, use the `color` spelling; update the package.
|
|
309
325
|
- **Sheets co-editing on the ordered log (C6).** `@ai-matrx/office/univer/collab` adds the Sheets room: `openSheetsOtRoom` (the C2 session over the C5a/C5b group transform, saves at a quiet point with a matching hash, restore through `collab_replace`, undo items rebased over every remote op), `univerSheetsOtPort` (capture: onlyLocal/fromCollab filtered, grouped by outermost command with a try/finally depth guard on both execute paths, params allowlist, completeCellContent, exact merge removals, style objects never ids, whole-style overrides restated as merges, annotateFormulas, inverses from the applied params against a pre-state copy; a barrier or unknown id is `not_shared` and rolls the seat back), `sheetsStateHash` / `canonicalSheet` (merges as a set, defined names by id; the transform fuzz now hashes through it), and `startWorkbookOtRoom` / `workbookUsesOrderedRoom` (the `udt_workbook_snapshots` store, the C1 doors, presence). A remote row/column insert, remove or move carries this seat's selection along and never leaves it past the sheet's edge (the port's `selections` option; a stale whole-row selection after a peer's column delete crashed the editor in the live run). Remote applies run with `{ fromCollab: true }` only (not `onlyLocal`): Univer's formula engine skips onlyLocal value writes, so a peer's formula showed blank on every other seat in the live run. Flip is per room exactly like Docs. Consumer action: matrx-frontend's WorkbookEditor opens it when the workbook's room exists or `collab.ot_rooms` says so (shipped with this release); every other consumer: none.
|
|
310
326
|
|
package/dist/pdf-model.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComingSoonEntry } from '@ai-matrx/kit/coming-soon';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The PDF workspace's tool rail, as data. Pure (no React, no icons): the host registers the
|
|
@@ -146,6 +146,8 @@ interface PdfViewerState {
|
|
|
146
146
|
rotations: Record<number, number>;
|
|
147
147
|
/** Changes when the file changed on the server: the viewer must load it again. */
|
|
148
148
|
reloadKey: number;
|
|
149
|
+
/** The page the person is on (1-based), passed only while a host tool with `followsPage` is open; otherwise 1. */
|
|
150
|
+
currentPage: number;
|
|
149
151
|
/** The document parsed with this many pages. */
|
|
150
152
|
onDocumentLoad(pageCount: number): void;
|
|
151
153
|
/** A page was measured, in PDF points (crop and fit-page need it). */
|
|
@@ -203,6 +205,38 @@ type PdfRunResult =
|
|
|
203
205
|
rows: string[][];
|
|
204
206
|
}>;
|
|
205
207
|
};
|
|
208
|
+
/** What the shell tells a host tool's panel about the session it sits in. */
|
|
209
|
+
interface PdfHostToolContext {
|
|
210
|
+
currentPage: number;
|
|
211
|
+
pageCount: number;
|
|
212
|
+
/** Original page numbers selected in the page panel (empty when none). */
|
|
213
|
+
selected: number[];
|
|
214
|
+
goToPage(n: number): void;
|
|
215
|
+
/** The file changed under the same id: draw the viewer and thumbnails again. */
|
|
216
|
+
reload(): void;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* A tool the host brings to the rail. The shell gives it a rail button, a place in "All tools", the
|
|
220
|
+
* tool search and the right panel; the host owns what is inside (its own server calls and state).
|
|
221
|
+
* This is how an app folds its older studios into the workspace without the package knowing them.
|
|
222
|
+
*/
|
|
223
|
+
interface PdfHostTool {
|
|
224
|
+
/** Unique among the host's tools. */
|
|
225
|
+
id: string;
|
|
226
|
+
label: string;
|
|
227
|
+
/** One short line under the panel title. */
|
|
228
|
+
hint?: string;
|
|
229
|
+
icon: ComponentType<{
|
|
230
|
+
className?: string;
|
|
231
|
+
}>;
|
|
232
|
+
/** The viewer receives `currentPage` while this tool is open (a one-page-at-a-time canvas needs it). */
|
|
233
|
+
followsPage?: boolean;
|
|
234
|
+
/** A wide panel (28rem) instead of the standard one (18rem). */
|
|
235
|
+
wide?: boolean;
|
|
236
|
+
/** Rail group: 1 (default) sits with the document tools. */
|
|
237
|
+
group?: 0 | 1 | 2;
|
|
238
|
+
render(context: PdfHostToolContext): ReactNode;
|
|
239
|
+
}
|
|
206
240
|
interface PdfWorkspaceHost {
|
|
207
241
|
file: {
|
|
208
242
|
id: string;
|
|
@@ -212,6 +246,8 @@ interface PdfWorkspaceHost {
|
|
|
212
246
|
renderViewer(state: PdfViewerState): ReactNode;
|
|
213
247
|
/** One page thumbnail (the left panel). Absent: the panel numbers its pages only. */
|
|
214
248
|
renderThumbnail?(page: number, widthPx: number): ReactNode;
|
|
249
|
+
/** A small badge drawn in the corner of one page's thumbnail (the app's annotation count, for example). Null or absent: none. */
|
|
250
|
+
renderPageBadge?(page: number): ReactNode;
|
|
215
251
|
/** Run one tool on the server. Rejects with a sentence on failure. */
|
|
216
252
|
run(request: PdfRunRequest): Promise<PdfRunResult>;
|
|
217
253
|
/** Open another page of the app for the same file (Scan, Sign). */
|
|
@@ -239,10 +275,12 @@ interface PdfWorkspaceHost {
|
|
|
239
275
|
id: string;
|
|
240
276
|
label: string;
|
|
241
277
|
}>>;
|
|
278
|
+
/** Extra tools the host brings (see `PdfHostTool`). */
|
|
279
|
+
tools?: PdfHostTool[];
|
|
242
280
|
/** False while the device is offline: the save pill says so and edits are not queued. */
|
|
243
281
|
online?: boolean;
|
|
244
282
|
/** Show a failure to the person (the host's toast). Defaults to an inline banner. */
|
|
245
283
|
notify?(message: string, tone: "error" | "info"): void;
|
|
246
284
|
}
|
|
247
285
|
|
|
248
|
-
export { HISTORY_LIMIT, type History, type KeyLike, PDF_COMING_SOON, PDF_SHORTCUTS, PDF_TOOLS, type PageDecisions, type PageOp, type PdfActionId, type PdfRunRequest, type PdfRunResult, type PdfShortcut, type PdfToolDef, type PdfToolId, type PdfViewerState, type PdfWorkspaceHost, type Turn, canRedo, canUndo, comingSoonIdOf, compilePageOps, deletePages, formatKeys, freshDecisions, isDirty, keptOrder, matchShortcut, pdfTool, pushStep, redo, redoLabel, reorderPages, restorePages, startHistory, turnPages, undo, undoLabel };
|
|
286
|
+
export { HISTORY_LIMIT, type History, type KeyLike, PDF_COMING_SOON, PDF_SHORTCUTS, PDF_TOOLS, type PageDecisions, type PageOp, type PdfActionId, type PdfHostTool, type PdfHostToolContext, type PdfRunRequest, type PdfRunResult, type PdfShortcut, type PdfToolDef, type PdfToolId, type PdfViewerState, type PdfWorkspaceHost, type Turn, canRedo, canUndo, comingSoonIdOf, compilePageOps, deletePages, formatKeys, freshDecisions, isDirty, keptOrder, matchShortcut, pdfTool, pushStep, redo, redoLabel, reorderPages, restorePages, startHistory, turnPages, undo, undoLabel };
|
package/dist/pdf-model.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComingSoonEntry } from '@ai-matrx/kit/coming-soon';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The PDF workspace's tool rail, as data. Pure (no React, no icons): the host registers the
|
|
@@ -146,6 +146,8 @@ interface PdfViewerState {
|
|
|
146
146
|
rotations: Record<number, number>;
|
|
147
147
|
/** Changes when the file changed on the server: the viewer must load it again. */
|
|
148
148
|
reloadKey: number;
|
|
149
|
+
/** The page the person is on (1-based), passed only while a host tool with `followsPage` is open; otherwise 1. */
|
|
150
|
+
currentPage: number;
|
|
149
151
|
/** The document parsed with this many pages. */
|
|
150
152
|
onDocumentLoad(pageCount: number): void;
|
|
151
153
|
/** A page was measured, in PDF points (crop and fit-page need it). */
|
|
@@ -203,6 +205,38 @@ type PdfRunResult =
|
|
|
203
205
|
rows: string[][];
|
|
204
206
|
}>;
|
|
205
207
|
};
|
|
208
|
+
/** What the shell tells a host tool's panel about the session it sits in. */
|
|
209
|
+
interface PdfHostToolContext {
|
|
210
|
+
currentPage: number;
|
|
211
|
+
pageCount: number;
|
|
212
|
+
/** Original page numbers selected in the page panel (empty when none). */
|
|
213
|
+
selected: number[];
|
|
214
|
+
goToPage(n: number): void;
|
|
215
|
+
/** The file changed under the same id: draw the viewer and thumbnails again. */
|
|
216
|
+
reload(): void;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* A tool the host brings to the rail. The shell gives it a rail button, a place in "All tools", the
|
|
220
|
+
* tool search and the right panel; the host owns what is inside (its own server calls and state).
|
|
221
|
+
* This is how an app folds its older studios into the workspace without the package knowing them.
|
|
222
|
+
*/
|
|
223
|
+
interface PdfHostTool {
|
|
224
|
+
/** Unique among the host's tools. */
|
|
225
|
+
id: string;
|
|
226
|
+
label: string;
|
|
227
|
+
/** One short line under the panel title. */
|
|
228
|
+
hint?: string;
|
|
229
|
+
icon: ComponentType<{
|
|
230
|
+
className?: string;
|
|
231
|
+
}>;
|
|
232
|
+
/** The viewer receives `currentPage` while this tool is open (a one-page-at-a-time canvas needs it). */
|
|
233
|
+
followsPage?: boolean;
|
|
234
|
+
/** A wide panel (28rem) instead of the standard one (18rem). */
|
|
235
|
+
wide?: boolean;
|
|
236
|
+
/** Rail group: 1 (default) sits with the document tools. */
|
|
237
|
+
group?: 0 | 1 | 2;
|
|
238
|
+
render(context: PdfHostToolContext): ReactNode;
|
|
239
|
+
}
|
|
206
240
|
interface PdfWorkspaceHost {
|
|
207
241
|
file: {
|
|
208
242
|
id: string;
|
|
@@ -212,6 +246,8 @@ interface PdfWorkspaceHost {
|
|
|
212
246
|
renderViewer(state: PdfViewerState): ReactNode;
|
|
213
247
|
/** One page thumbnail (the left panel). Absent: the panel numbers its pages only. */
|
|
214
248
|
renderThumbnail?(page: number, widthPx: number): ReactNode;
|
|
249
|
+
/** A small badge drawn in the corner of one page's thumbnail (the app's annotation count, for example). Null or absent: none. */
|
|
250
|
+
renderPageBadge?(page: number): ReactNode;
|
|
215
251
|
/** Run one tool on the server. Rejects with a sentence on failure. */
|
|
216
252
|
run(request: PdfRunRequest): Promise<PdfRunResult>;
|
|
217
253
|
/** Open another page of the app for the same file (Scan, Sign). */
|
|
@@ -239,10 +275,12 @@ interface PdfWorkspaceHost {
|
|
|
239
275
|
id: string;
|
|
240
276
|
label: string;
|
|
241
277
|
}>>;
|
|
278
|
+
/** Extra tools the host brings (see `PdfHostTool`). */
|
|
279
|
+
tools?: PdfHostTool[];
|
|
242
280
|
/** False while the device is offline: the save pill says so and edits are not queued. */
|
|
243
281
|
online?: boolean;
|
|
244
282
|
/** Show a failure to the person (the host's toast). Defaults to an inline banner. */
|
|
245
283
|
notify?(message: string, tone: "error" | "info"): void;
|
|
246
284
|
}
|
|
247
285
|
|
|
248
|
-
export { HISTORY_LIMIT, type History, type KeyLike, PDF_COMING_SOON, PDF_SHORTCUTS, PDF_TOOLS, type PageDecisions, type PageOp, type PdfActionId, type PdfRunRequest, type PdfRunResult, type PdfShortcut, type PdfToolDef, type PdfToolId, type PdfViewerState, type PdfWorkspaceHost, type Turn, canRedo, canUndo, comingSoonIdOf, compilePageOps, deletePages, formatKeys, freshDecisions, isDirty, keptOrder, matchShortcut, pdfTool, pushStep, redo, redoLabel, reorderPages, restorePages, startHistory, turnPages, undo, undoLabel };
|
|
286
|
+
export { HISTORY_LIMIT, type History, type KeyLike, PDF_COMING_SOON, PDF_SHORTCUTS, PDF_TOOLS, type PageDecisions, type PageOp, type PdfActionId, type PdfHostTool, type PdfHostToolContext, type PdfRunRequest, type PdfRunResult, type PdfShortcut, type PdfToolDef, type PdfToolId, type PdfViewerState, type PdfWorkspaceHost, type Turn, canRedo, canUndo, comingSoonIdOf, compilePageOps, deletePages, formatKeys, freshDecisions, isDirty, keptOrder, matchShortcut, pdfTool, pushStep, redo, redoLabel, reorderPages, restorePages, startHistory, turnPages, undo, undoLabel };
|
package/dist/pdf.cjs
CHANGED
|
@@ -157,6 +157,7 @@ function LeftPanel(p) {
|
|
|
157
157
|
const turn = p.decisions.turns[page] ?? 0;
|
|
158
158
|
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
159
|
/* @__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 }) }),
|
|
160
|
+
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
161
|
page === p.currentPage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pointer-events-none absolute inset-0 border-2 border-primary" }) : null,
|
|
161
162
|
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
163
|
] });
|
|
@@ -585,25 +586,41 @@ function useWidth(ref) {
|
|
|
585
586
|
}, [ref]);
|
|
586
587
|
return size;
|
|
587
588
|
}
|
|
588
|
-
function ToolRows({ tool, onPick }) {
|
|
589
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
590
|
-
|
|
591
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
589
|
+
function ToolRows({ tool, hostTools, onPick }) {
|
|
590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
591
|
+
hostTools.map((t) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
592
592
|
"button",
|
|
593
593
|
{
|
|
594
594
|
type: "button",
|
|
595
595
|
role: "menuitem",
|
|
596
|
-
"aria-current": t.id
|
|
597
|
-
className: (0, import_cn.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
|
|
598
|
-
onClick: () => onPick(t.id),
|
|
596
|
+
"aria-current": tool === `host:${t.id}` ? "true" : void 0,
|
|
597
|
+
className: (0, import_cn.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
|
+
onClick: () => onPick(`host:${t.id}`),
|
|
599
599
|
children: [
|
|
600
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
601
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex-1 whitespace-nowrap", children: t.label })
|
|
602
|
-
t.status === "soon" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-muted-foreground", children: "Coming soon" }) : null
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(t.icon, { className: "size-4 shrink-0" }),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex-1 whitespace-nowrap", children: t.label })
|
|
603
602
|
]
|
|
604
603
|
}
|
|
605
|
-
) }, t.id)
|
|
606
|
-
|
|
604
|
+
) }, `host:${t.id}`)),
|
|
605
|
+
PDF_TOOLS.filter((t) => t.id !== "browse").map((t) => {
|
|
606
|
+
const Icon = PDF_TOOL_ICONS[t.id];
|
|
607
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
608
|
+
"button",
|
|
609
|
+
{
|
|
610
|
+
type: "button",
|
|
611
|
+
role: "menuitem",
|
|
612
|
+
"aria-current": t.id === tool ? "true" : void 0,
|
|
613
|
+
className: (0, import_cn.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
|
+
onClick: () => onPick(t.id),
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { className: "size-4 shrink-0" }),
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "flex-1 whitespace-nowrap", children: t.label }),
|
|
618
|
+
t.status === "soon" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-muted-foreground", children: "Coming soon" }) : null
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
) }, t.id);
|
|
622
|
+
})
|
|
623
|
+
] });
|
|
607
624
|
}
|
|
608
625
|
function PdfWorkspace({ host, className }) {
|
|
609
626
|
const rootRef = (0, import_react3.useRef)(null);
|
|
@@ -617,6 +634,10 @@ function PdfWorkspace({ host, className }) {
|
|
|
617
634
|
const decisions = history.present.value;
|
|
618
635
|
const dirty = isDirty(decisions);
|
|
619
636
|
const [tool, setTool] = (0, import_react3.useState)("browse");
|
|
637
|
+
const [hostToolId, setHostToolId] = (0, import_react3.useState)(null);
|
|
638
|
+
const hostTools = (0, import_react3.useMemo)(() => host.tools ?? [], [host.tools]);
|
|
639
|
+
const hostTool = hostToolId ? hostTools.find((t) => t.id === hostToolId) ?? null : null;
|
|
640
|
+
const activeToolKey = hostTool ? `host:${hostTool.id}` : tool;
|
|
620
641
|
const [leftOpen, setLeftOpen] = (0, import_react3.useState)(true);
|
|
621
642
|
const [rightOpen, setRightOpen] = (0, import_react3.useState)(true);
|
|
622
643
|
const [leftTab, setLeftTab] = (0, import_react3.useState)("pages");
|
|
@@ -769,8 +790,17 @@ function PdfWorkspace({ host, className }) {
|
|
|
769
790
|
const discard = (0, import_react3.useCallback)(() => setHistory(startHistory(freshDecisions(pageCount))), [pageCount]);
|
|
770
791
|
const chooseTool = (0, import_react3.useCallback)(
|
|
771
792
|
(id) => {
|
|
793
|
+
if (id.startsWith("host:")) {
|
|
794
|
+
setHostToolId(id.slice(5));
|
|
795
|
+
setResult(null);
|
|
796
|
+
setError(null);
|
|
797
|
+
setRightOpen(true);
|
|
798
|
+
if (compact) setSheet("tools");
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
772
801
|
const def = pdfTool(id);
|
|
773
802
|
if (!def) return;
|
|
803
|
+
setHostToolId(null);
|
|
774
804
|
if (def.status === "soon") {
|
|
775
805
|
announceSoon(comingSoonIdOf(def.id)).catch(fail);
|
|
776
806
|
return;
|
|
@@ -793,9 +823,10 @@ function PdfWorkspace({ host, className }) {
|
|
|
793
823
|
if (t.status !== "ready") continue;
|
|
794
824
|
groups[t.group].push({ id: t.id, label: t.label, icon: PDF_TOOL_ICONS[t.id], ...t.key ? { shortcut: t.key.toUpperCase() } : null });
|
|
795
825
|
}
|
|
826
|
+
for (const t of hostTools) groups[t.group ?? 1].push({ id: `host:${t.id}`, label: t.label, icon: t.icon });
|
|
796
827
|
groups[2].push({ id: ALL_TOOLS, label: "All tools", icon: import_icons2.MoreHorizontalIcon });
|
|
797
828
|
return groups.filter((g) => g.length);
|
|
798
|
-
}, []);
|
|
829
|
+
}, [hostTools]);
|
|
799
830
|
const runAction = (0, import_react3.useCallback)(
|
|
800
831
|
(action) => {
|
|
801
832
|
if (action.startsWith("tool:")) return chooseTool(action.slice(5));
|
|
@@ -883,7 +914,10 @@ function PdfWorkspace({ host, className }) {
|
|
|
883
914
|
}
|
|
884
915
|
);
|
|
885
916
|
const iconBtn = (label, icon, onClick, opts) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.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 });
|
|
886
|
-
const toolHits = toolQuery.trim() ?
|
|
917
|
+
const toolHits = toolQuery.trim() ? [
|
|
918
|
+
...hostTools.map((t) => ({ id: `host:${t.id}`, label: t.label, status: "ready" })),
|
|
919
|
+
...PDF_TOOLS
|
|
920
|
+
].filter((t) => t.label.toLowerCase().includes(toolQuery.trim().toLowerCase())) : [];
|
|
887
921
|
const nameNode = editingName && host.rename ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
888
922
|
import_controls4.Field,
|
|
889
923
|
{
|
|
@@ -914,7 +948,13 @@ function PdfWorkspace({ host, className }) {
|
|
|
914
948
|
children: host.file.name
|
|
915
949
|
}
|
|
916
950
|
);
|
|
917
|
-
const rightPanel = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
951
|
+
const rightPanel = hostTool ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex h-full min-h-0 flex-col", "data-pdf-host-tool": hostTool.id, children: [
|
|
952
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "shrink-0 border-b border-border px-3 py-2", children: [
|
|
953
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-sm font-medium", children: hostTool.label }),
|
|
954
|
+
hostTool.hint ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: hostTool.hint }) : null
|
|
955
|
+
] }),
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "min-h-0 flex-1 overflow-hidden", children: hostTool.render({ currentPage, pageCount, selected: selectedPages, goToPage, reload: () => setReloadKey((k) => k + 1) }) })
|
|
957
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
918
958
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "shrink-0 border-b border-border px-3 py-2", children: [
|
|
919
959
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-sm font-medium", children: toolDef.label }),
|
|
920
960
|
toolDef.hint ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs text-muted-foreground", children: toolDef.hint }) : null
|
|
@@ -961,9 +1001,10 @@ function PdfWorkspace({ host, className }) {
|
|
|
961
1001
|
onLayersSoon: () => void announceSoon("pdf.layers").catch(fail)
|
|
962
1002
|
}
|
|
963
1003
|
);
|
|
1004
|
+
const viewerPage = hostTool?.followsPage ? currentPage : 1;
|
|
964
1005
|
const viewer = (0, import_react3.useMemo)(
|
|
965
|
-
() => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react3.Fragment, { children: host.renderViewer({ zoom, spread, rotations: decisions.turns, reloadKey, onDocumentLoad, onPageSize }) }, reloadKey),
|
|
966
|
-
[host, reloadKey, zoom, spread, decisions.turns, onDocumentLoad, onPageSize]
|
|
1006
|
+
() => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react3.Fragment, { children: host.renderViewer({ zoom, spread, rotations: decisions.turns, reloadKey, currentPage: viewerPage, onDocumentLoad, onPageSize }) }, reloadKey),
|
|
1007
|
+
[host, reloadKey, zoom, spread, decisions.turns, viewerPage, onDocumentLoad, onPageSize]
|
|
967
1008
|
);
|
|
968
1009
|
const showChrome = !read;
|
|
969
1010
|
const popCard = "absolute right-2 top-11 z-30 rounded-lg border border-border bg-popover p-3 text-popover-foreground shadow-lg";
|
|
@@ -1076,15 +1117,15 @@ function PdfWorkspace({ host, className }) {
|
|
|
1076
1117
|
iconBtn("Reading mode", /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons2.ExpandIcon, {}), () => setRead(true))
|
|
1077
1118
|
] }) : null,
|
|
1078
1119
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative flex min-h-0 flex-1", children: [
|
|
1079
|
-
showChrome && !compact ? /* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)(import_controls4.ToolRail, { groups: railGroups, value: pop === "all-tools" ? ALL_TOOLS :
|
|
1120
|
+
showChrome && !compact ? /* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)(import_controls4.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,
|
|
1080
1121
|
showChrome && !compact && leftOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("aside", { className: "w-56 shrink-0 border-r border-border bg-background", "aria-label": "Pages", "data-pdf-left": "", children: leftPanel }) : null,
|
|
1081
1122
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("main", { className: "relative flex min-w-0 flex-1 flex-col", children: [
|
|
1082
1123
|
findOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute right-4 top-2 z-20", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_RenderedFindBar.RenderedFindBar, { rootRef: scrollerRef, onClose: () => setFindOpen(false), label: "Find in document", focusRequest: findFocus, compact: true }) }) : null,
|
|
1083
1124
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: scrollerRef, tabIndex: 0, "data-pdf-scroller": "", className: "min-h-0 flex-1 overflow-auto bg-muted outline-none", children: viewer }),
|
|
1084
1125
|
read ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute right-3 top-3 z-20", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_controls4.Button, { variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_icons2.XIcon, {}), onClick: () => setRead(false), children: "Exit reading mode" }) }) : null
|
|
1085
1126
|
] }),
|
|
1086
|
-
showChrome && !compact && rightOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("aside", { className: "
|
|
1087
|
-
pop === "all-tools" ? /* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)(ToolRows, { tool, onPick: (id) => {
|
|
1127
|
+
showChrome && !compact && rightOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("aside", { className: (0, import_cn.cn)("shrink-0 border-l border-border bg-background", hostTool?.wide ? "w-[28rem]" : "w-72"), "aria-label": "Properties", "data-pdf-right": "", children: rightPanel }) : null,
|
|
1128
|
+
pop === "all-tools" ? /* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)(ToolRows, { tool: activeToolKey, hostTools, onPick: (id) => {
|
|
1088
1129
|
setPop(null);
|
|
1089
1130
|
chooseTool(id);
|
|
1090
1131
|
} }) }) : null,
|
|
@@ -1115,7 +1156,7 @@ function PdfWorkspace({ host, className }) {
|
|
|
1115
1156
|
compact && sheet ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1116
1157
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "aria-label": "Close", className: "absolute inset-0 z-30 bg-background/60", onClick: () => setSheet(null) }),
|
|
1117
1158
|
/* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)("div", { className: "h-[60vh] min-h-0", children: leftPanel }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex min-h-0 flex-col overflow-y-auto", children: [
|
|
1118
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "p-2", role: "menu", "aria-label": "Tools", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRows, { tool, onPick: chooseTool }) }),
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "p-2", role: "menu", "aria-label": "Tools", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRows, { tool: activeToolKey, hostTools, onPick: chooseTool }) }),
|
|
1119
1160
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "border-t border-border", children: rightPanel })
|
|
1120
1161
|
] }) })
|
|
1121
1162
|
] }) : null
|