@printwithsynergy/lens-pdf 0.3.0-beta.81
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/LICENSE +661 -0
- package/README.md +344 -0
- package/dist/browser/codexOverlay.d.ts +109 -0
- package/dist/browser/codexOverlay.d.ts.map +1 -0
- package/dist/browser/codexOverlay.js +256 -0
- package/dist/browser/codexOverlay.js.map +1 -0
- package/dist/browser/constants.d.ts +13 -0
- package/dist/browser/constants.d.ts.map +1 -0
- package/dist/browser/constants.js +13 -0
- package/dist/browser/constants.js.map +1 -0
- package/dist/browser/index.d.ts +211 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +1190 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/pantone-gold.d.ts +59 -0
- package/dist/browser/pantone-gold.d.ts.map +1 -0
- package/dist/browser/pantone-gold.js +237 -0
- package/dist/browser/pantone-gold.js.map +1 -0
- package/dist/components/AnnotationCanvas.d.ts +27 -0
- package/dist/components/AnnotationCanvas.d.ts.map +1 -0
- package/dist/components/AnnotationCanvas.js +401 -0
- package/dist/components/AnnotationCanvas.js.map +1 -0
- package/dist/components/AnnotationNotesPanel.d.ts +15 -0
- package/dist/components/AnnotationNotesPanel.d.ts.map +1 -0
- package/dist/components/AnnotationNotesPanel.js +235 -0
- package/dist/components/AnnotationNotesPanel.js.map +1 -0
- package/dist/components/AnnotationThread.d.ts +18 -0
- package/dist/components/AnnotationThread.d.ts.map +1 -0
- package/dist/components/AnnotationThread.js +163 -0
- package/dist/components/AnnotationThread.js.map +1 -0
- package/dist/components/AnnotationToolbar.d.ts +39 -0
- package/dist/components/AnnotationToolbar.d.ts.map +1 -0
- package/dist/components/AnnotationToolbar.js +258 -0
- package/dist/components/AnnotationToolbar.js.map +1 -0
- package/dist/components/BoxOverlay.d.ts +20 -0
- package/dist/components/BoxOverlay.d.ts.map +1 -0
- package/dist/components/BoxOverlay.js +107 -0
- package/dist/components/BoxOverlay.js.map +1 -0
- package/dist/components/ColorPickerTool.d.ts +11 -0
- package/dist/components/ColorPickerTool.d.ts.map +1 -0
- package/dist/components/ColorPickerTool.js +220 -0
- package/dist/components/ColorPickerTool.js.map +1 -0
- package/dist/components/DensitometerTool.d.ts +25 -0
- package/dist/components/DensitometerTool.d.ts.map +1 -0
- package/dist/components/DensitometerTool.js +246 -0
- package/dist/components/DensitometerTool.js.map +1 -0
- package/dist/components/DielineInfoPanel.d.ts +27 -0
- package/dist/components/DielineInfoPanel.d.ts.map +1 -0
- package/dist/components/DielineInfoPanel.js +23 -0
- package/dist/components/DielineInfoPanel.js.map +1 -0
- package/dist/components/DielineOverlay.d.ts +10 -0
- package/dist/components/DielineOverlay.d.ts.map +1 -0
- package/dist/components/DielineOverlay.js +57 -0
- package/dist/components/DielineOverlay.js.map +1 -0
- package/dist/components/FindingsSidebar.d.ts +50 -0
- package/dist/components/FindingsSidebar.d.ts.map +1 -0
- package/dist/components/FindingsSidebar.js +78 -0
- package/dist/components/FindingsSidebar.js.map +1 -0
- package/dist/components/LayerCanvas.d.ts +30 -0
- package/dist/components/LayerCanvas.d.ts.map +1 -0
- package/dist/components/LayerCanvas.js +84 -0
- package/dist/components/LayerCanvas.js.map +1 -0
- package/dist/components/LayerPanel.d.ts +9 -0
- package/dist/components/LayerPanel.d.ts.map +1 -0
- package/dist/components/LayerPanel.js +144 -0
- package/dist/components/LayerPanel.js.map +1 -0
- package/dist/components/LensPDF.d.ts +61 -0
- package/dist/components/LensPDF.d.ts.map +1 -0
- package/dist/components/LensPDF.js +49 -0
- package/dist/components/LensPDF.js.map +1 -0
- package/dist/components/LensPDFDemo.d.ts +160 -0
- package/dist/components/LensPDFDemo.d.ts.map +1 -0
- package/dist/components/LensPDFDemo.js +1060 -0
- package/dist/components/LensPDFDemo.js.map +1 -0
- package/dist/components/LensPDFDemo.styles.d.ts +38 -0
- package/dist/components/LensPDFDemo.styles.d.ts.map +1 -0
- package/dist/components/LensPDFDemo.styles.js +282 -0
- package/dist/components/LensPDFDemo.styles.js.map +1 -0
- package/dist/components/LensPDFViewer.d.ts +79 -0
- package/dist/components/LensPDFViewer.d.ts.map +1 -0
- package/dist/components/LensPDFViewer.js +254 -0
- package/dist/components/LensPDFViewer.js.map +1 -0
- package/dist/components/MeasureTool.d.ts +16 -0
- package/dist/components/MeasureTool.d.ts.map +1 -0
- package/dist/components/MeasureTool.js +137 -0
- package/dist/components/MeasureTool.js.map +1 -0
- package/dist/components/MobileBottomSheet.d.ts +12 -0
- package/dist/components/MobileBottomSheet.d.ts.map +1 -0
- package/dist/components/MobileBottomSheet.js +113 -0
- package/dist/components/MobileBottomSheet.js.map +1 -0
- package/dist/components/MobileDrawer.d.ts +31 -0
- package/dist/components/MobileDrawer.d.ts.map +1 -0
- package/dist/components/MobileDrawer.js +67 -0
- package/dist/components/MobileDrawer.js.map +1 -0
- package/dist/components/PageCanvas.d.ts +33 -0
- package/dist/components/PageCanvas.d.ts.map +1 -0
- package/dist/components/PageCanvas.js +385 -0
- package/dist/components/PageCanvas.js.map +1 -0
- package/dist/components/PageNavigator.d.ts +18 -0
- package/dist/components/PageNavigator.d.ts.map +1 -0
- package/dist/components/PageNavigator.js +44 -0
- package/dist/components/PageNavigator.js.map +1 -0
- package/dist/components/SeparationCanvas.d.ts +12 -0
- package/dist/components/SeparationCanvas.d.ts.map +1 -0
- package/dist/components/SeparationCanvas.js +174 -0
- package/dist/components/SeparationCanvas.js.map +1 -0
- package/dist/components/TACHeatmapOverlay.d.ts +17 -0
- package/dist/components/TACHeatmapOverlay.d.ts.map +1 -0
- package/dist/components/TACHeatmapOverlay.js +119 -0
- package/dist/components/TACHeatmapOverlay.js.map +1 -0
- package/dist/components/ZoomControls.d.ts +11 -0
- package/dist/components/ZoomControls.d.ts.map +1 -0
- package/dist/components/ZoomControls.js +26 -0
- package/dist/components/ZoomControls.js.map +1 -0
- package/dist/components/defaultShellPlugins.d.ts +3 -0
- package/dist/components/defaultShellPlugins.d.ts.map +1 -0
- package/dist/components/defaultShellPlugins.js +273 -0
- package/dist/components/defaultShellPlugins.js.map +1 -0
- package/dist/components/index.d.ts +32 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +32 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/presets.d.ts +8 -0
- package/dist/components/presets.d.ts.map +1 -0
- package/dist/components/presets.js +14 -0
- package/dist/components/presets.js.map +1 -0
- package/dist/components/shellPlugins.d.ts +105 -0
- package/dist/components/shellPlugins.d.ts.map +1 -0
- package/dist/components/shellPlugins.js +52 -0
- package/dist/components/shellPlugins.js.map +1 -0
- package/dist/components/useIsMobile.d.ts +16 -0
- package/dist/components/useIsMobile.d.ts.map +1 -0
- package/dist/components/useIsMobile.js +30 -0
- package/dist/components/useIsMobile.js.map +1 -0
- package/dist/fallback-pdfjs/index.d.ts +60 -0
- package/dist/fallback-pdfjs/index.d.ts.map +1 -0
- package/dist/fallback-pdfjs/index.js +163 -0
- package/dist/fallback-pdfjs/index.js.map +1 -0
- package/dist/host/LensPDFProvider.d.ts +36 -0
- package/dist/host/LensPDFProvider.d.ts.map +1 -0
- package/dist/host/LensPDFProvider.js +12 -0
- package/dist/host/LensPDFProvider.js.map +1 -0
- package/dist/host/index.d.ts +167 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +173 -0
- package/dist/host/index.js.map +1 -0
- package/dist/host/pdfFallback.d.ts +50 -0
- package/dist/host/pdfFallback.d.ts.map +1 -0
- package/dist/host/pdfFallback.js +171 -0
- package/dist/host/pdfFallback.js.map +1 -0
- package/dist/host/pdfValidation.d.ts +45 -0
- package/dist/host/pdfValidation.d.ts.map +1 -0
- package/dist/host/pdfValidation.js +78 -0
- package/dist/host/pdfValidation.js.map +1 -0
- package/dist/host/shareLink.d.ts +80 -0
- package/dist/host/shareLink.d.ts.map +1 -0
- package/dist/host/shareLink.js +114 -0
- package/dist/host/shareLink.js.map +1 -0
- package/dist/host/useLensPDF.d.ts +73 -0
- package/dist/host/useLensPDF.d.ts.map +1 -0
- package/dist/host/useLensPDF.js +213 -0
- package/dist/host/useLensPDF.js.map +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/context.d.ts +70 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +16 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/findings-location.d.ts +53 -0
- package/dist/plugin/findings-location.d.ts.map +1 -0
- package/dist/plugin/findings-location.js +72 -0
- package/dist/plugin/findings-location.js.map +1 -0
- package/dist/plugin/index.d.ts +19 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +16 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/registry.d.ts +61 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/registry.js +102 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/services.d.ts +380 -0
- package/dist/plugin/services.d.ts.map +1 -0
- package/dist/plugin/services.js +104 -0
- package/dist/plugin/services.js.map +1 -0
- package/dist/plugin/types.d.ts +198 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +24 -0
- package/dist/plugin/types.js.map +1 -0
- package/dist/types/index.d.ts +191 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +95 -0
- package/dist/types/index.js.map +1 -0
- package/dist/units/index.d.ts +64 -0
- package/dist/units/index.d.ts.map +1 -0
- package/dist/units/index.js +98 -0
- package/dist/units/index.js.map +1 -0
- package/docs/architecture.md +90 -0
- package/docs/components.md +569 -0
- package/docs/contributing.md +78 -0
- package/docs/fallback.md +174 -0
- package/docs/lens-pdf-viewer.md +128 -0
- package/docs/licensing.md +78 -0
- package/docs/measurement-units.md +87 -0
- package/docs/plugins.md +256 -0
- package/docs/security.md +69 -0
- package/docs/server.md +212 -0
- package/docs/services.md +210 -0
- package/docs/share-links.md +111 -0
- package/docs/theming.md +164 -0
- package/docs/validation.md +83 -0
- package/package.json +139 -0
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Component reference"
|
|
3
|
+
description: "Per-component props, slots, and usage for every React component the package exports — page canvas, navigator, separations, layers, annotations, mobile chrome."
|
|
4
|
+
group: "Reference"
|
|
5
|
+
order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Component reference
|
|
9
|
+
|
|
10
|
+
Every component is imported from `@printwithsynergy/lens-pdf/components`
|
|
11
|
+
and reads its data through the contexts described in
|
|
12
|
+
[architecture.md](./architecture.md). Required `ViewerServices` fields are
|
|
13
|
+
called out per component.
|
|
14
|
+
|
|
15
|
+
- [Drop-in viewer](#drop-in-viewer)
|
|
16
|
+
- [Drop-in demo](#drop-in-demo)
|
|
17
|
+
- [Page rendering](#page-rendering)
|
|
18
|
+
- [Print-production overlays](#print-production-overlays)
|
|
19
|
+
- [Sampling tools](#sampling-tools)
|
|
20
|
+
- [Layer & separation modes](#layer--separation-modes)
|
|
21
|
+
- [Annotations](#annotations)
|
|
22
|
+
- [Mobile chrome](#mobile-chrome)
|
|
23
|
+
|
|
24
|
+
## Drop-in viewer
|
|
25
|
+
|
|
26
|
+
### `LensPDF`
|
|
27
|
+
|
|
28
|
+
The recommended single-component entry point for production hosts.
|
|
29
|
+
One mount, every viewer-only feature wired to pdf.js out of the box —
|
|
30
|
+
page tile (multi-DPI cache), color picker, densitometer, measure
|
|
31
|
+
tool, TAC heatmap, per-ink separations (CMYK + spots), OCG layers,
|
|
32
|
+
and the annotation toolbar / canvas / thread. No upload chrome — the
|
|
33
|
+
host supplies the URL.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { LensPDF } from "@printwithsynergy/lens-pdf";
|
|
37
|
+
import pdfWorkerSrc from "pdfjs-dist/build/pdf.worker.mjs?url";
|
|
38
|
+
|
|
39
|
+
export function ProofPage() {
|
|
40
|
+
return <LensPDF pdfUrl="/proofs/abc.pdf" workerSrc={pdfWorkerSrc} />;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
#### Props
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Notes |
|
|
47
|
+
| --- | --- | --- | --- |
|
|
48
|
+
| `pdfUrl` | `string` | _(required)_ | PDF the viewer will load. Changing it swaps the document and resets to `initialPage`. |
|
|
49
|
+
| `workerSrc` | `string` | `defaultBrowserWorkerSrc` | Override the pdf.js worker URL. |
|
|
50
|
+
| `services` | `ViewerServices` | _browser services_ | Pass wired services to swap any feature from the in-browser approximation to a backend. |
|
|
51
|
+
| `tools` | `ReadonlyArray<LensPDFDemoTool>` | all | Subset of tools to show in the sidebar. |
|
|
52
|
+
| `initialZoom` | `number` | `80` | Starting zoom percentage. |
|
|
53
|
+
| `initialPage` | `number` | `1` | Starting page (1-indexed). |
|
|
54
|
+
| `tacLimit` | `number` | `300` | TAC limit (in percent) for the heatmap + densitometer. |
|
|
55
|
+
| `tokens` | `Partial<ThemeTokens>` | `darkThemeTokens` | Theme override merged onto the dark palette. Add `logoUrl` / `logoText` / `logoMaxHeight` / `logoAlt` to bundle brand identity into the tokens object. |
|
|
56
|
+
| `brand` / `brandLogoUrl` | `string` | _(none)_ | Optional brand label / logo. Falls back to `tokens.logoText` / `tokens.logoUrl` when the props are unset. |
|
|
57
|
+
| `items` | `OverlayItem[]` | `[]` | Preflight findings (error / warning / advisory bboxes). |
|
|
58
|
+
| `selectedItem` | `OverlayItem \| null` | _(internal)_ | Controlled selection. |
|
|
59
|
+
| `onItemSelect` | `(item) => void` | _(internal)_ | Selection callback. |
|
|
60
|
+
| `forceInspectionPanel` | `boolean` | `false` | Force the Inspection / Findings side panel visible even when `items` is empty (renders a "no findings yet" empty state). Useful for demos that always advertise the panel slot, or for hosts with an in-flight preflight call. When false (default), the panel auto-shows when `items.length > 0` and hides otherwise. |
|
|
61
|
+
| `spotPalette` | `Record<string, string>` | `undefined` | Host-provided spot-colour palette (keyed by spot name). Takes priority over the built-in Pantone Gold library and the PDF's `altRgb` fallback in the separations-panel swatch render. Typical source: codex's `summary.spot_colors.colors[].swatch_hex` or another preflight's swatch hex. |
|
|
62
|
+
| `dieline` | `DielineResult \| null` | _(none)_ | Dieline geometry overlay. |
|
|
63
|
+
| `showBoxOverlays` | `boolean` | `false` | Render trim / bleed / crop popovers. |
|
|
64
|
+
| `cropToTrim` | `boolean` | `false` | Clip the canvas to the page's TrimBox (falls back to BleedBox, then CropBox). |
|
|
65
|
+
| `fullscreen` | `boolean` | `false` | Fixed-position full-viewport mode. |
|
|
66
|
+
| `footer` | `ReactNode` | _(none)_ | Extra content in the footer bar. |
|
|
67
|
+
| `className` | `string` | _(none)_ | Class on the outermost div. |
|
|
68
|
+
| `preset` | `"demo" \| "minimal"` | `"minimal"` | First-party plugin preset baseline. |
|
|
69
|
+
| `plugins` | `ReadonlyArray<LensPDFShellPlugin>` | `[]` | Extra shell plugins; use `replaces` to override built-ins. |
|
|
70
|
+
| `codex` | `MinimalCodexClient` | _(none)_ | Optional codex client; when set, the viewer silently upgrades separations / TAC / layers to Ghostscript-rendered plates as `extractStream` events arrive. |
|
|
71
|
+
| `onPageChange` / `onZoomChange` / `onError` | callbacks | _(none)_ | Lifecycle hooks. |
|
|
72
|
+
|
|
73
|
+
CMYK / TAC are RGB-derived approximations when no backend is wired.
|
|
74
|
+
For ICC-correct readings, deploy the [optional reference server](./server.md)
|
|
75
|
+
and pass its `services` overrides.
|
|
76
|
+
|
|
77
|
+
The `codex` prop accepts any object matching the structural
|
|
78
|
+
`MinimalCodexClient` interface — in practice that means an instance of
|
|
79
|
+
`HttpClient` from `@printwithsynergy/codex-client@^1.8.1`, declared as
|
|
80
|
+
an optional peer dep. Hosts that don't use the codex overlay don't need
|
|
81
|
+
to install it.
|
|
82
|
+
|
|
83
|
+
## Drop-in demo
|
|
84
|
+
|
|
85
|
+
### `LensPDFDemo`
|
|
86
|
+
|
|
87
|
+
Marketing / showcase variant of `<LensPDF>` — adds an upload bar,
|
|
88
|
+
URL paste, drag-and-drop, client-side PDF validation, and an
|
|
89
|
+
empty-state UI. Useful for `lenspdf.com`-style demo pages and
|
|
90
|
+
internal sandboxes where users bring their own files. **Most
|
|
91
|
+
consumers should reach for [`<LensPDF>`](#lenspdf) instead.**
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { LensPDFDemo } from "@printwithsynergy/lens-pdf";
|
|
95
|
+
|
|
96
|
+
export function DemoPage() {
|
|
97
|
+
return <LensPDFDemo brand="MyApp" brandLogoUrl="/logo.svg" />;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Props
|
|
102
|
+
|
|
103
|
+
| Prop | Type | Default | Notes |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| `brand` | `string` | `tokens.logoText` ?? `"LensPDF"` | Label in the top bar. |
|
|
106
|
+
| `brandLogoUrl` | `string` | `tokens.logoUrl` | Logo image URL. |
|
|
107
|
+
| `tokens` | `Partial<ThemeTokens>` | `darkThemeTokens` | Merged onto the dark palette. Add `logoUrl` / `logoText` / `logoMaxHeight` / `logoAlt` to bundle brand identity into the tokens object. |
|
|
108
|
+
| `maxFileSize` | `number` | `50 * 1024 * 1024` (50 MB) | Max upload size in bytes. |
|
|
109
|
+
| `services` | `ViewerServices` | _browser services_ | Optional overrides for hosts with a backend. Unwired fields auto-fall through to the in-browser pdf.js services. |
|
|
110
|
+
| `workerSrc` | `string` | `defaultBrowserWorkerSrc` | Override the pdf.js worker URL. |
|
|
111
|
+
| `initialZoom` | `number` | `80` | Starting zoom percentage. |
|
|
112
|
+
| `tacLimit` | `number` | `300` | TAC limit (in percent) for the heatmap + densitometer. |
|
|
113
|
+
| `fullscreen` | `boolean` | `false` | Fixed-position full-viewport mode. |
|
|
114
|
+
| `initialPdfUrl` | `string` | _(none)_ | Pre-loaded PDF URL (e.g. from [share-link params](./share-links.md)). |
|
|
115
|
+
| `initialPage` | `number` | `1` | Starting page (1-indexed). |
|
|
116
|
+
| `footer` | `ReactNode` | _(none)_ | Extra content in the footer bar. |
|
|
117
|
+
| `className` | `string` | _(none)_ | Class on the outermost div. |
|
|
118
|
+
| `tools` | `ReadonlyArray<LensPDFDemoTool>` | all | Feature ids to keep enabled (`color-picker`, `densitometer`, `measure`, `annotate`, `tac-heatmap`, `separations`, `layers`). |
|
|
119
|
+
| `items` / `selectedItem` / `onItemSelect` | preflight props | _(none)_ | Same as on `<LensPDF>` — preflight findings + controlled selection. |
|
|
120
|
+
| `dieline` / `showBoxOverlays` / `cropToTrim` | print-production props | _(off / none)_ | Same as on `<LensPDF>`. |
|
|
121
|
+
| `onPageChange` / `onZoomChange` / `onError` | callbacks | _(none)_ | Lifecycle hooks. |
|
|
122
|
+
| `preset` | `"demo" \| "minimal"` | `"demo"` | First-party plugin preset baseline. `LensPDF` uses `"minimal"`. |
|
|
123
|
+
| `plugins` | `ReadonlyArray<LensPDFShellPlugin>` | `[]` | Extra shell plugins; use `replaces` to override built-ins. |
|
|
124
|
+
| `codex` | `MinimalCodexClient` | _(none)_ | Optional codex client; when set, the viewer silently upgrades separations / TAC / layers to Ghostscript-rendered plates as `extractStream` events arrive. |
|
|
125
|
+
|
|
126
|
+
#### Built-in features
|
|
127
|
+
|
|
128
|
+
- **File upload** — opens a native file picker (`application/pdf`).
|
|
129
|
+
- **URL paste** — form input validates via `validatePdfUrl()`.
|
|
130
|
+
- **Drag-and-drop** — drop anywhere on the component.
|
|
131
|
+
- **Validation** — checks PDF magic bytes (`%PDF-`), MIME type, and
|
|
132
|
+
size. See [validation.md](./validation.md).
|
|
133
|
+
- **Sidebar** — zoom slider, tool toggles, layer panel.
|
|
134
|
+
- **Fullscreen** — `fullscreen` prop renders with `position: fixed; inset: 0`.
|
|
135
|
+
Combine with [shareable links](./share-links.md) for fullscreen share URLs.
|
|
136
|
+
- **Blob lifecycle** — created blob URLs are revoked on PDF change and
|
|
137
|
+
on unmount.
|
|
138
|
+
- **Plugin shell** — left panels + annotation toolbar are mounted from
|
|
139
|
+
slot plugins (`panel.left`, `overlay.toolbar`) via built-in presets.
|
|
140
|
+
- **Inspection / Findings panel** — when the host passes `items` (any
|
|
141
|
+
`OverlayItem[]`), the side drawer leads with an `Inspection (N)`
|
|
142
|
+
section: tier filter chips (errors / warnings / advisories / info)
|
|
143
|
+
+ a clickable list that drives `onItemSelect` for canvas highlight
|
|
144
|
+
+ page jump. Renders nothing when `items` is empty, so OSS hosts
|
|
145
|
+
without preflight don't see an empty section. Pass
|
|
146
|
+
`forceInspectionPanel` to keep the slot mounted even with no items
|
|
147
|
+
(useful for in-flight preflight calls or demos that advertise the
|
|
148
|
+
feature from the first frame).
|
|
149
|
+
- **Spot-colour palette resolution** — the separations panel resolves
|
|
150
|
+
each spot swatch in this order: host-provided `spotPalette[name]`
|
|
151
|
+
→ built-in Pantone Gold library (~85 most-common Coated codes,
|
|
152
|
+
tolerates case + `C` / `U` suffixes + `PMS` prefix) → the PDF
|
|
153
|
+
tint-transform `altRgb` parsed at extraction → neutral grey
|
|
154
|
+
fallback. Hosts with codex output typically pass
|
|
155
|
+
`summary.spot_colors.colors[].swatch_hex` through to `spotPalette`
|
|
156
|
+
for the truest swatch.
|
|
157
|
+
|
|
158
|
+
#### Custom sidebar/menu composition
|
|
159
|
+
|
|
160
|
+
`LensPDFDemo` and `LensPDF` now expose a plugin-first shell for the
|
|
161
|
+
viewer chrome. You can replace built-ins without forking:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import {
|
|
165
|
+
LensPDF,
|
|
166
|
+
type LensPDFShellPlugin,
|
|
167
|
+
} from "@printwithsynergy/lens-pdf/components";
|
|
168
|
+
|
|
169
|
+
const customNotesPanel: LensPDFShellPlugin = {
|
|
170
|
+
id: "acme.panel.notes",
|
|
171
|
+
slot: "panel.left",
|
|
172
|
+
order: 40,
|
|
173
|
+
replaces: "lens.annotations-panel",
|
|
174
|
+
render(ctx) {
|
|
175
|
+
return (
|
|
176
|
+
<section>
|
|
177
|
+
<h2>My Notes</h2>
|
|
178
|
+
<button onClick={() => ctx.setCurrentPage(1)}>Jump to page 1</button>
|
|
179
|
+
</section>
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export function ProofPage() {
|
|
185
|
+
return (
|
|
186
|
+
<LensPDF
|
|
187
|
+
pdfUrl="/proofs/abc.pdf"
|
|
188
|
+
plugins={[customNotesPanel]}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Page rendering
|
|
195
|
+
|
|
196
|
+
### `PageCanvas`
|
|
197
|
+
|
|
198
|
+
The main page tile. Renders the page image from `services.pageImages`, draws
|
|
199
|
+
bounding boxes for every `OverlayItem`, and fires `onItemClick` when one is
|
|
200
|
+
clicked. Optional `cropToTrim` clips the canvas to the page's trim box
|
|
201
|
+
(falls back to bleed, then crop).
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
<PageCanvas
|
|
205
|
+
jobId="demo"
|
|
206
|
+
page={page} // PageInfo
|
|
207
|
+
zoom={1} // multiplier; 1.0 = 100%
|
|
208
|
+
items={overlayItems} // readonly OverlayItem[]
|
|
209
|
+
selectedItem={selected} // OverlayItem | null
|
|
210
|
+
onItemClick={setSelected}
|
|
211
|
+
onZoomChange={(z) => setZoom(z * 100)}
|
|
212
|
+
onPageChange={(delta) => setCurrentPage((p) => p + delta)}
|
|
213
|
+
tileDpi={150}
|
|
214
|
+
tileCdnBase={null}
|
|
215
|
+
cropToTrim={false}
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Service deps: `pageImages.getPageImageUrl`.
|
|
220
|
+
|
|
221
|
+
### `PageNavigator`
|
|
222
|
+
|
|
223
|
+
Vertical or horizontal thumbnail strip with per-page overlay-item badges.
|
|
224
|
+
`items` accepts the same `OverlayItem[]` you pass to `PageCanvas`; the
|
|
225
|
+
navigator counts `tier === "error"` and `tier === "warning"` per page and
|
|
226
|
+
draws the appropriate badge.
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
<PageNavigator
|
|
230
|
+
pages={pages} // PageInfo[]
|
|
231
|
+
currentPage={currentPage}
|
|
232
|
+
items={overlayItems}
|
|
233
|
+
onPageChange={setCurrentPage}
|
|
234
|
+
horizontal={false} // true → strip, false → vertical sidebar
|
|
235
|
+
/>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Service deps: `pageImages.getPageImageUrl` (rendered at `THUMBNAIL_DPI = 72`).
|
|
239
|
+
|
|
240
|
+
### `ZoomControls`
|
|
241
|
+
|
|
242
|
+
`+` / `−` buttons plus a percentage select. `zoom` is a percentage; the
|
|
243
|
+
steps are `[25, 50, 75, 100, 125, 150, 200, 300, 400]`.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
<ZoomControls
|
|
247
|
+
zoom={zoom} // number, percent
|
|
248
|
+
onZoomChange={setZoom}
|
|
249
|
+
compact={false} // smaller buttons, no border
|
|
250
|
+
dark={false} // light text on dark bg
|
|
251
|
+
/>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Print-production overlays
|
|
255
|
+
|
|
256
|
+
### `BoxOverlay`
|
|
257
|
+
|
|
258
|
+
Trim, Bleed, and Crop box outlines with a clickable info icon per box that
|
|
259
|
+
reveals the dimensions in mm + inches. Pass an optional `dieline` payload
|
|
260
|
+
(`DielineResult`) to also drop a per-region info chip at the centroid of
|
|
261
|
+
each artwork cut area.
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
<BoxOverlay
|
|
265
|
+
page={page}
|
|
266
|
+
canvasWidth={renderedWidth}
|
|
267
|
+
canvasHeight={renderedHeight}
|
|
268
|
+
dieline={dielineResult} // optional DielineResult | null
|
|
269
|
+
/>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `DielineOverlay`
|
|
273
|
+
|
|
274
|
+
Standalone dieline-region chips. Renders independently of `BoxOverlay` so
|
|
275
|
+
users can see dieline sizes without enabling the trim/bleed boxes UI.
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<DielineOverlay
|
|
279
|
+
page={page}
|
|
280
|
+
canvasWidth={renderedWidth}
|
|
281
|
+
canvasHeight={renderedHeight}
|
|
282
|
+
dieline={dielineResult}
|
|
283
|
+
/>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Sampling tools
|
|
287
|
+
|
|
288
|
+
### `ColorPickerTool`
|
|
289
|
+
|
|
290
|
+
Click anywhere on the page to read the rendered RGB + hex + TAC at that
|
|
291
|
+
PDF point. Calls `services.colorSample.sampleAt`. Returns `null` on
|
|
292
|
+
failure; the tool simply displays nothing rather than throwing.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
<ColorPickerTool
|
|
296
|
+
jobId="demo"
|
|
297
|
+
pageNum={1}
|
|
298
|
+
pageWidthPts={page.width_pts}
|
|
299
|
+
pageHeightPts={page.height_pts}
|
|
300
|
+
canvasWidth={renderedWidth}
|
|
301
|
+
canvasHeight={renderedHeight}
|
|
302
|
+
/>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Service deps: `colorSample.sampleAt`.
|
|
306
|
+
|
|
307
|
+
### `DensitometerTool`
|
|
308
|
+
|
|
309
|
+
Same shape as `ColorPickerTool`, but reads CMYK + spot-channel percentages
|
|
310
|
+
and Total Area Coverage via `services.densitometer.sampleAt`. Optional
|
|
311
|
+
`tacLimit` (defaults to `300`).
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
<DensitometerTool
|
|
315
|
+
jobId="demo"
|
|
316
|
+
pageNum={1}
|
|
317
|
+
pageWidthPts={page.width_pts}
|
|
318
|
+
pageHeightPts={page.height_pts}
|
|
319
|
+
canvasWidth={renderedWidth}
|
|
320
|
+
canvasHeight={renderedHeight}
|
|
321
|
+
tacLimit={300}
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Service deps: `densitometer.sampleAt`. See
|
|
326
|
+
[services.md](./services.md#densitometer) for the error-message contract.
|
|
327
|
+
|
|
328
|
+
### `MeasureTool`
|
|
329
|
+
|
|
330
|
+
Click-and-drag a ruler. Reports the distance in PDF points and through each
|
|
331
|
+
unit you supply (defaults to `[mm, in, pt]`).
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
<MeasureTool
|
|
335
|
+
pageWidthPts={page.width_pts}
|
|
336
|
+
pageHeightPts={page.height_pts}
|
|
337
|
+
canvasWidth={renderedWidth}
|
|
338
|
+
canvasHeight={renderedHeight}
|
|
339
|
+
units={defaultMeasurementUnits}
|
|
340
|
+
/>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
See [measurement-units.md](./measurement-units.md) for the unit Protocol
|
|
344
|
+
and built-ins.
|
|
345
|
+
|
|
346
|
+
### `TACHeatmapOverlay`
|
|
347
|
+
|
|
348
|
+
An SVG hover layer over the page tile that places a hit rectangle at each
|
|
349
|
+
text run and shows its mean TAC on hover. Reads both an image URL and the
|
|
350
|
+
per-run list from `services.tacHeatmap`.
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
<TACHeatmapOverlay
|
|
354
|
+
jobId="demo"
|
|
355
|
+
pageNum={1}
|
|
356
|
+
width={renderedWidth}
|
|
357
|
+
height={renderedHeight}
|
|
358
|
+
pageWidthPts={page.width_pts}
|
|
359
|
+
pageHeightPts={page.height_pts}
|
|
360
|
+
opacity={0.5}
|
|
361
|
+
dpi={150}
|
|
362
|
+
tacLimit={300}
|
|
363
|
+
/>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Service deps: `tacHeatmap.getHeatmapImageUrl`, `tacHeatmap.listRuns`.
|
|
367
|
+
|
|
368
|
+
## Layer & separation modes
|
|
369
|
+
|
|
370
|
+
### `LayerCanvas`
|
|
371
|
+
|
|
372
|
+
Instant layer toggling via per-OCG isolated tiles. The host renders one
|
|
373
|
+
PNG per layer with a transparent background; the browser composites the
|
|
374
|
+
active subset locally with `source-over` blending. Toggling a layer is a
|
|
375
|
+
redraw, not a network round-trip. The first paint of an unseen layer
|
|
376
|
+
takes 1–3 s (engine + cache write); subsequent toggles hit the cache
|
|
377
|
+
and complete in well under 100 ms.
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
<LayerCanvas
|
|
381
|
+
jobId="demo"
|
|
382
|
+
pageNum={1}
|
|
383
|
+
enabledLayers={enabled} // Set<number> of OCG indices
|
|
384
|
+
allLayers={allOcgIndices} // number[] in drawing order
|
|
385
|
+
width={renderedWidth}
|
|
386
|
+
height={renderedHeight}
|
|
387
|
+
dpi={DEFAULT_DPI}
|
|
388
|
+
/>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Service deps: `layers.getLayerImageUrl`.
|
|
392
|
+
|
|
393
|
+
### `LayerPanel`
|
|
394
|
+
|
|
395
|
+
Companion UI: a checklist of OCGs with toggle / show-all / hide-all
|
|
396
|
+
controls. Pulls the OCG list from `services.layers.listLayers`.
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
<LayerPanel
|
|
400
|
+
jobId="demo"
|
|
401
|
+
enabledLayers={enabled}
|
|
402
|
+
onToggleLayer={(idx) => /* … */}
|
|
403
|
+
onSetAllLayers={(on) => /* … */}
|
|
404
|
+
/>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Service deps: `layers.listLayers`.
|
|
408
|
+
|
|
409
|
+
### `SeparationCanvas`
|
|
410
|
+
|
|
411
|
+
Same instant-toggle pattern, but per ink channel (Cyan, Magenta, Yellow,
|
|
412
|
+
Black, plus any spot inks). Uses subtractive multiply blending against a
|
|
413
|
+
white background. Spot inks get a deterministic HSL hue derived from the
|
|
414
|
+
channel name when no engine-provided RGB is available.
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
<SeparationCanvas
|
|
418
|
+
jobId="demo"
|
|
419
|
+
pageNum={1}
|
|
420
|
+
enabledChannels={enabledChannels} // Set<string>
|
|
421
|
+
allChannels={["Cyan", "Magenta", "Yellow", "Black", "Pantone 185 C"]}
|
|
422
|
+
width={renderedWidth}
|
|
423
|
+
height={renderedHeight}
|
|
424
|
+
dpi={DEFAULT_DPI}
|
|
425
|
+
/>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Service deps: `separations.getChannelImageUrl`.
|
|
429
|
+
|
|
430
|
+
## Annotations
|
|
431
|
+
|
|
432
|
+
The annotation suite needs the optional `fabric@^7` peer dep installed in
|
|
433
|
+
your host app, and respects `ViewerHostContext.readOnly` to suppress
|
|
434
|
+
saves in share-link / public-token modes.
|
|
435
|
+
|
|
436
|
+
### `AnnotationToolbar`
|
|
437
|
+
|
|
438
|
+
A tool-and-color toolbar. Supported tools are `pointer`, `pen`, `arrow`,
|
|
439
|
+
`rectangle`, `ellipse`, `text`, and `highlight`. The host owns the
|
|
440
|
+
active-tool state and undo/redo stack.
|
|
441
|
+
|
|
442
|
+
```tsx
|
|
443
|
+
<AnnotationToolbar
|
|
444
|
+
activeTool={tool} // AnnotationTool
|
|
445
|
+
onToolChange={setTool}
|
|
446
|
+
strokeColor={color}
|
|
447
|
+
onStrokeColorChange={setColor}
|
|
448
|
+
onUndo={undo}
|
|
449
|
+
onRedo={redo}
|
|
450
|
+
canUndo={canUndo}
|
|
451
|
+
canRedo={canRedo}
|
|
452
|
+
saving={saving}
|
|
453
|
+
/>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### `AnnotationCanvas`
|
|
457
|
+
|
|
458
|
+
Fabric.js canvas overlay. Autosaves the current page's drawing through
|
|
459
|
+
`services.annotations.saveForPage`. Skips saves when
|
|
460
|
+
`ViewerHostContext.readOnly` is true. Calls `onSavingChange` and
|
|
461
|
+
`onHistoryChange` so a parent toolbar can show a saving spinner and
|
|
462
|
+
disable undo/redo correctly.
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
<AnnotationCanvas
|
|
466
|
+
jobId="demo"
|
|
467
|
+
pageNum={1}
|
|
468
|
+
width={renderedWidth}
|
|
469
|
+
height={renderedHeight}
|
|
470
|
+
activeTool={tool}
|
|
471
|
+
strokeColor={color}
|
|
472
|
+
onSavingChange={setSaving}
|
|
473
|
+
onHistoryChange={(canUndo, canRedo) => /* … */}
|
|
474
|
+
/>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Service deps: `annotations.getForPage`, `annotations.saveForPage`. Renders
|
|
478
|
+
nothing when `services.annotations` is unwired (see
|
|
479
|
+
[fallback.md](./fallback.md)).
|
|
480
|
+
|
|
481
|
+
### `AnnotationThread`
|
|
482
|
+
|
|
483
|
+
Sidebar list of annotations across every page, loaded from
|
|
484
|
+
`services.annotations.list`. Calls `onJumpToPage` when the user clicks a
|
|
485
|
+
row.
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
<AnnotationThread
|
|
489
|
+
jobId="demo"
|
|
490
|
+
currentUserEmail="ops@example.com"
|
|
491
|
+
onJumpToPage={setCurrentPage}
|
|
492
|
+
/>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Service deps: `annotations.list`, `annotations.remove`. Renders nothing
|
|
496
|
+
when `services.annotations` is unwired (see [fallback.md](./fallback.md)).
|
|
497
|
+
|
|
498
|
+
## Mobile chrome
|
|
499
|
+
|
|
500
|
+
### `useIsMobile`
|
|
501
|
+
|
|
502
|
+
Hook that returns `true` when `window.matchMedia("(max-width: 767px)")`
|
|
503
|
+
matches. Used internally by `<LensPDF>` / `<LensPDFDemo>` to switch
|
|
504
|
+
the tools sidebar into a slide-in drawer (anchored to the left edge,
|
|
505
|
+
~85vw wide, max 320 px) and to switch the color-picker / densitometer
|
|
506
|
+
readouts from floating tooltips to full-width bottom sheets.
|
|
507
|
+
|
|
508
|
+
```tsx
|
|
509
|
+
import { useIsMobile } from "@printwithsynergy/lens-pdf/components";
|
|
510
|
+
|
|
511
|
+
const isMobile = useIsMobile(); // default 767 px breakpoint
|
|
512
|
+
const isTablet = useIsMobile(1024); // custom breakpoint
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### `MobileDrawer`
|
|
516
|
+
|
|
517
|
+
A slide-out config drawer for phones, mirroring the desktop sidebar.
|
|
518
|
+
Driven by a `ViewerConfig` (`enable_*` capability flags + plan-gate
|
|
519
|
+
booleans), with section toggles for separation / layer / annotation /
|
|
520
|
+
heatmap / box-overlay modes and external links to the HTML report and
|
|
521
|
+
PDF download.
|
|
522
|
+
|
|
523
|
+
`ViewerConfig` is a fairly large shape — see `types/index.ts` for the full
|
|
524
|
+
field list, and `DEFAULT_VIEWER_CONFIG` for sensible defaults.
|
|
525
|
+
|
|
526
|
+
```tsx
|
|
527
|
+
<MobileDrawer
|
|
528
|
+
isOpen={drawerOpen}
|
|
529
|
+
onClose={() => setDrawerOpen(false)}
|
|
530
|
+
config={config}
|
|
531
|
+
viewerMode={viewerMode} // "normal" | "separation" | "layers" | …
|
|
532
|
+
onToggleMode={setViewerMode}
|
|
533
|
+
measureMode={measureMode} // "none" | "color_picker" | "densitometer" | "ruler"
|
|
534
|
+
onToggleMeasure={setMeasureMode}
|
|
535
|
+
showTacHeatmap={tac}
|
|
536
|
+
onToggleTacHeatmap={() => setTac((v) => !v)}
|
|
537
|
+
showBoxOverlay={boxes}
|
|
538
|
+
onToggleBoxOverlay={() => setBoxes((v) => !v)}
|
|
539
|
+
fileName="design.pdf"
|
|
540
|
+
findingSummary={{ error: 0, warning: 2, advisory: 5 }}
|
|
541
|
+
zoom={zoom}
|
|
542
|
+
onZoomChange={setZoom}
|
|
543
|
+
jobId="demo"
|
|
544
|
+
onExpandSheet={() => sheetRef.current?.expand()}
|
|
545
|
+
onOpenShare={() => /* … */}
|
|
546
|
+
/>
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
Service deps: `reports.getHtmlReportUrl`, `reports.getPdfDownloadUrl`. The
|
|
550
|
+
"View HTML Report" and "Download PDF" items are dropped when
|
|
551
|
+
`services.reports` is unwired even if the matching `config.enable_*` flag
|
|
552
|
+
is on (see [fallback.md](./fallback.md)).
|
|
553
|
+
|
|
554
|
+
### `MobileBottomSheet`
|
|
555
|
+
|
|
556
|
+
A drag-snap bottom sheet with `collapsed`, `half`, and `full` positions.
|
|
557
|
+
Auto-sizes the `half` position to its content. Accepts `summary` (always
|
|
558
|
+
visible) and `children` (revealed at `half` / `full`). Snap can be
|
|
559
|
+
controlled or uncontrolled.
|
|
560
|
+
|
|
561
|
+
```tsx
|
|
562
|
+
<MobileBottomSheet
|
|
563
|
+
summary={<FindingSummaryRow />}
|
|
564
|
+
snap={snap}
|
|
565
|
+
onSnapChange={setSnap}
|
|
566
|
+
>
|
|
567
|
+
<FindingDetailList />
|
|
568
|
+
</MobileBottomSheet>
|
|
569
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Contributing"
|
|
3
|
+
description: "Boundary rule, provenance, local development workflow, public-API surface, commit and PR style, and license terms for contributors."
|
|
4
|
+
group: "Project"
|
|
5
|
+
order: 9
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Contributing
|
|
9
|
+
|
|
10
|
+
Notes for contributors to LensPDF itself. End-user / host docs live
|
|
11
|
+
elsewhere in [`docs/`](.).
|
|
12
|
+
|
|
13
|
+
## Boundary rule
|
|
14
|
+
|
|
15
|
+
The viewer core MUST NOT import:
|
|
16
|
+
|
|
17
|
+
- any host- or product-specific package or path,
|
|
18
|
+
- a literal backend route string anywhere in source — every URL is
|
|
19
|
+
composed by a `ViewerServices` URL builder the host supplies.
|
|
20
|
+
|
|
21
|
+
CI typecheck catches type-level violations (missing types, unresolved
|
|
22
|
+
imports, banned protocol shapes); reviewers enforce the spirit of the
|
|
23
|
+
boundary on every PR. Anything domain-shaped (findings,
|
|
24
|
+
brand-spec violations, audit verdicts, host-specific configuration)
|
|
25
|
+
lives in plugin packs — the core namespace stays unbranded so any
|
|
26
|
+
host can mount it with zero coupling to a particular SaaS.
|
|
27
|
+
|
|
28
|
+
When you add a new feature, ask:
|
|
29
|
+
|
|
30
|
+
- Does it talk to a backend? → It's a `ViewerServices` field.
|
|
31
|
+
- Does it draw on top of the page or in a panel/toolbar? → It's a plugin.
|
|
32
|
+
- Does it depend on a domain shape (a finding, an annotation
|
|
33
|
+
interpretation, a brand spec)? → It does not belong in `core/`.
|
|
34
|
+
|
|
35
|
+
## Provenance
|
|
36
|
+
|
|
37
|
+
This package was extracted from an upstream SaaS monorepo via
|
|
38
|
+
`git subtree split` over `packages/viewer-shared/src/core/`. History
|
|
39
|
+
is file-scoped; the synthetic root commit (`c77ccc51`) is the start
|
|
40
|
+
of this repo's history. Everything host-specific from the original
|
|
41
|
+
monorepo lives in separate downstream plugin packs — none of it is
|
|
42
|
+
imported here.
|
|
43
|
+
|
|
44
|
+
## Local development
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
npm install
|
|
48
|
+
npm run typecheck # tsc -p tsconfig.json
|
|
49
|
+
npm test # vitest run
|
|
50
|
+
npm run build # tsc -p tsconfig.build.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The repo doesn't track a `package-lock.json` (libraries leave that to
|
|
54
|
+
consuming apps). Add tests alongside new components — `vitest` is
|
|
55
|
+
already wired up; see `plugin/services.test.ts` for the existing
|
|
56
|
+
pattern.
|
|
57
|
+
|
|
58
|
+
## Public API surface
|
|
59
|
+
|
|
60
|
+
Anything exported from a barrel (`index.ts` at the package root, or
|
|
61
|
+
`{components,plugin,host,types,units}/index.ts`) is part of the public
|
|
62
|
+
API and should be considered semver-stable once the package goes public.
|
|
63
|
+
Keep `@public` JSDoc tags accurate when you add or remove exports — they
|
|
64
|
+
double as the contract for downstream consumers.
|
|
65
|
+
|
|
66
|
+
## Commit / PR style
|
|
67
|
+
|
|
68
|
+
- Conventional-commit prefixes (`feat:`, `fix:`, `docs:`, `chore:`,
|
|
69
|
+
`refactor:`, `test:`, `ci:`, `build:`).
|
|
70
|
+
- Keep PRs small and focused; one feature or one cleanup per branch.
|
|
71
|
+
- Match the existing code's no-comment-by-default policy — write the WHY
|
|
72
|
+
only when the WHY is non-obvious.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
LensPDF is AGPL-3.0-or-later. By contributing you agree to license your
|
|
77
|
+
contribution under the same terms. See [`LICENSE`](../LICENSE) for the
|
|
78
|
+
full text.
|