@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.
Files changed (213) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +344 -0
  3. package/dist/browser/codexOverlay.d.ts +109 -0
  4. package/dist/browser/codexOverlay.d.ts.map +1 -0
  5. package/dist/browser/codexOverlay.js +256 -0
  6. package/dist/browser/codexOverlay.js.map +1 -0
  7. package/dist/browser/constants.d.ts +13 -0
  8. package/dist/browser/constants.d.ts.map +1 -0
  9. package/dist/browser/constants.js +13 -0
  10. package/dist/browser/constants.js.map +1 -0
  11. package/dist/browser/index.d.ts +211 -0
  12. package/dist/browser/index.d.ts.map +1 -0
  13. package/dist/browser/index.js +1190 -0
  14. package/dist/browser/index.js.map +1 -0
  15. package/dist/browser/pantone-gold.d.ts +59 -0
  16. package/dist/browser/pantone-gold.d.ts.map +1 -0
  17. package/dist/browser/pantone-gold.js +237 -0
  18. package/dist/browser/pantone-gold.js.map +1 -0
  19. package/dist/components/AnnotationCanvas.d.ts +27 -0
  20. package/dist/components/AnnotationCanvas.d.ts.map +1 -0
  21. package/dist/components/AnnotationCanvas.js +401 -0
  22. package/dist/components/AnnotationCanvas.js.map +1 -0
  23. package/dist/components/AnnotationNotesPanel.d.ts +15 -0
  24. package/dist/components/AnnotationNotesPanel.d.ts.map +1 -0
  25. package/dist/components/AnnotationNotesPanel.js +235 -0
  26. package/dist/components/AnnotationNotesPanel.js.map +1 -0
  27. package/dist/components/AnnotationThread.d.ts +18 -0
  28. package/dist/components/AnnotationThread.d.ts.map +1 -0
  29. package/dist/components/AnnotationThread.js +163 -0
  30. package/dist/components/AnnotationThread.js.map +1 -0
  31. package/dist/components/AnnotationToolbar.d.ts +39 -0
  32. package/dist/components/AnnotationToolbar.d.ts.map +1 -0
  33. package/dist/components/AnnotationToolbar.js +258 -0
  34. package/dist/components/AnnotationToolbar.js.map +1 -0
  35. package/dist/components/BoxOverlay.d.ts +20 -0
  36. package/dist/components/BoxOverlay.d.ts.map +1 -0
  37. package/dist/components/BoxOverlay.js +107 -0
  38. package/dist/components/BoxOverlay.js.map +1 -0
  39. package/dist/components/ColorPickerTool.d.ts +11 -0
  40. package/dist/components/ColorPickerTool.d.ts.map +1 -0
  41. package/dist/components/ColorPickerTool.js +220 -0
  42. package/dist/components/ColorPickerTool.js.map +1 -0
  43. package/dist/components/DensitometerTool.d.ts +25 -0
  44. package/dist/components/DensitometerTool.d.ts.map +1 -0
  45. package/dist/components/DensitometerTool.js +246 -0
  46. package/dist/components/DensitometerTool.js.map +1 -0
  47. package/dist/components/DielineInfoPanel.d.ts +27 -0
  48. package/dist/components/DielineInfoPanel.d.ts.map +1 -0
  49. package/dist/components/DielineInfoPanel.js +23 -0
  50. package/dist/components/DielineInfoPanel.js.map +1 -0
  51. package/dist/components/DielineOverlay.d.ts +10 -0
  52. package/dist/components/DielineOverlay.d.ts.map +1 -0
  53. package/dist/components/DielineOverlay.js +57 -0
  54. package/dist/components/DielineOverlay.js.map +1 -0
  55. package/dist/components/FindingsSidebar.d.ts +50 -0
  56. package/dist/components/FindingsSidebar.d.ts.map +1 -0
  57. package/dist/components/FindingsSidebar.js +78 -0
  58. package/dist/components/FindingsSidebar.js.map +1 -0
  59. package/dist/components/LayerCanvas.d.ts +30 -0
  60. package/dist/components/LayerCanvas.d.ts.map +1 -0
  61. package/dist/components/LayerCanvas.js +84 -0
  62. package/dist/components/LayerCanvas.js.map +1 -0
  63. package/dist/components/LayerPanel.d.ts +9 -0
  64. package/dist/components/LayerPanel.d.ts.map +1 -0
  65. package/dist/components/LayerPanel.js +144 -0
  66. package/dist/components/LayerPanel.js.map +1 -0
  67. package/dist/components/LensPDF.d.ts +61 -0
  68. package/dist/components/LensPDF.d.ts.map +1 -0
  69. package/dist/components/LensPDF.js +49 -0
  70. package/dist/components/LensPDF.js.map +1 -0
  71. package/dist/components/LensPDFDemo.d.ts +160 -0
  72. package/dist/components/LensPDFDemo.d.ts.map +1 -0
  73. package/dist/components/LensPDFDemo.js +1060 -0
  74. package/dist/components/LensPDFDemo.js.map +1 -0
  75. package/dist/components/LensPDFDemo.styles.d.ts +38 -0
  76. package/dist/components/LensPDFDemo.styles.d.ts.map +1 -0
  77. package/dist/components/LensPDFDemo.styles.js +282 -0
  78. package/dist/components/LensPDFDemo.styles.js.map +1 -0
  79. package/dist/components/LensPDFViewer.d.ts +79 -0
  80. package/dist/components/LensPDFViewer.d.ts.map +1 -0
  81. package/dist/components/LensPDFViewer.js +254 -0
  82. package/dist/components/LensPDFViewer.js.map +1 -0
  83. package/dist/components/MeasureTool.d.ts +16 -0
  84. package/dist/components/MeasureTool.d.ts.map +1 -0
  85. package/dist/components/MeasureTool.js +137 -0
  86. package/dist/components/MeasureTool.js.map +1 -0
  87. package/dist/components/MobileBottomSheet.d.ts +12 -0
  88. package/dist/components/MobileBottomSheet.d.ts.map +1 -0
  89. package/dist/components/MobileBottomSheet.js +113 -0
  90. package/dist/components/MobileBottomSheet.js.map +1 -0
  91. package/dist/components/MobileDrawer.d.ts +31 -0
  92. package/dist/components/MobileDrawer.d.ts.map +1 -0
  93. package/dist/components/MobileDrawer.js +67 -0
  94. package/dist/components/MobileDrawer.js.map +1 -0
  95. package/dist/components/PageCanvas.d.ts +33 -0
  96. package/dist/components/PageCanvas.d.ts.map +1 -0
  97. package/dist/components/PageCanvas.js +385 -0
  98. package/dist/components/PageCanvas.js.map +1 -0
  99. package/dist/components/PageNavigator.d.ts +18 -0
  100. package/dist/components/PageNavigator.d.ts.map +1 -0
  101. package/dist/components/PageNavigator.js +44 -0
  102. package/dist/components/PageNavigator.js.map +1 -0
  103. package/dist/components/SeparationCanvas.d.ts +12 -0
  104. package/dist/components/SeparationCanvas.d.ts.map +1 -0
  105. package/dist/components/SeparationCanvas.js +174 -0
  106. package/dist/components/SeparationCanvas.js.map +1 -0
  107. package/dist/components/TACHeatmapOverlay.d.ts +17 -0
  108. package/dist/components/TACHeatmapOverlay.d.ts.map +1 -0
  109. package/dist/components/TACHeatmapOverlay.js +119 -0
  110. package/dist/components/TACHeatmapOverlay.js.map +1 -0
  111. package/dist/components/ZoomControls.d.ts +11 -0
  112. package/dist/components/ZoomControls.d.ts.map +1 -0
  113. package/dist/components/ZoomControls.js +26 -0
  114. package/dist/components/ZoomControls.js.map +1 -0
  115. package/dist/components/defaultShellPlugins.d.ts +3 -0
  116. package/dist/components/defaultShellPlugins.d.ts.map +1 -0
  117. package/dist/components/defaultShellPlugins.js +273 -0
  118. package/dist/components/defaultShellPlugins.js.map +1 -0
  119. package/dist/components/index.d.ts +32 -0
  120. package/dist/components/index.d.ts.map +1 -0
  121. package/dist/components/index.js +32 -0
  122. package/dist/components/index.js.map +1 -0
  123. package/dist/components/presets.d.ts +8 -0
  124. package/dist/components/presets.d.ts.map +1 -0
  125. package/dist/components/presets.js +14 -0
  126. package/dist/components/presets.js.map +1 -0
  127. package/dist/components/shellPlugins.d.ts +105 -0
  128. package/dist/components/shellPlugins.d.ts.map +1 -0
  129. package/dist/components/shellPlugins.js +52 -0
  130. package/dist/components/shellPlugins.js.map +1 -0
  131. package/dist/components/useIsMobile.d.ts +16 -0
  132. package/dist/components/useIsMobile.d.ts.map +1 -0
  133. package/dist/components/useIsMobile.js +30 -0
  134. package/dist/components/useIsMobile.js.map +1 -0
  135. package/dist/fallback-pdfjs/index.d.ts +60 -0
  136. package/dist/fallback-pdfjs/index.d.ts.map +1 -0
  137. package/dist/fallback-pdfjs/index.js +163 -0
  138. package/dist/fallback-pdfjs/index.js.map +1 -0
  139. package/dist/host/LensPDFProvider.d.ts +36 -0
  140. package/dist/host/LensPDFProvider.d.ts.map +1 -0
  141. package/dist/host/LensPDFProvider.js +12 -0
  142. package/dist/host/LensPDFProvider.js.map +1 -0
  143. package/dist/host/index.d.ts +167 -0
  144. package/dist/host/index.d.ts.map +1 -0
  145. package/dist/host/index.js +173 -0
  146. package/dist/host/index.js.map +1 -0
  147. package/dist/host/pdfFallback.d.ts +50 -0
  148. package/dist/host/pdfFallback.d.ts.map +1 -0
  149. package/dist/host/pdfFallback.js +171 -0
  150. package/dist/host/pdfFallback.js.map +1 -0
  151. package/dist/host/pdfValidation.d.ts +45 -0
  152. package/dist/host/pdfValidation.d.ts.map +1 -0
  153. package/dist/host/pdfValidation.js +78 -0
  154. package/dist/host/pdfValidation.js.map +1 -0
  155. package/dist/host/shareLink.d.ts +80 -0
  156. package/dist/host/shareLink.d.ts.map +1 -0
  157. package/dist/host/shareLink.js +114 -0
  158. package/dist/host/shareLink.js.map +1 -0
  159. package/dist/host/useLensPDF.d.ts +73 -0
  160. package/dist/host/useLensPDF.d.ts.map +1 -0
  161. package/dist/host/useLensPDF.js +213 -0
  162. package/dist/host/useLensPDF.js.map +1 -0
  163. package/dist/index.d.ts +68 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +62 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/plugin/context.d.ts +70 -0
  168. package/dist/plugin/context.d.ts.map +1 -0
  169. package/dist/plugin/context.js +16 -0
  170. package/dist/plugin/context.js.map +1 -0
  171. package/dist/plugin/findings-location.d.ts +53 -0
  172. package/dist/plugin/findings-location.d.ts.map +1 -0
  173. package/dist/plugin/findings-location.js +72 -0
  174. package/dist/plugin/findings-location.js.map +1 -0
  175. package/dist/plugin/index.d.ts +19 -0
  176. package/dist/plugin/index.d.ts.map +1 -0
  177. package/dist/plugin/index.js +16 -0
  178. package/dist/plugin/index.js.map +1 -0
  179. package/dist/plugin/registry.d.ts +61 -0
  180. package/dist/plugin/registry.d.ts.map +1 -0
  181. package/dist/plugin/registry.js +102 -0
  182. package/dist/plugin/registry.js.map +1 -0
  183. package/dist/plugin/services.d.ts +380 -0
  184. package/dist/plugin/services.d.ts.map +1 -0
  185. package/dist/plugin/services.js +104 -0
  186. package/dist/plugin/services.js.map +1 -0
  187. package/dist/plugin/types.d.ts +198 -0
  188. package/dist/plugin/types.d.ts.map +1 -0
  189. package/dist/plugin/types.js +24 -0
  190. package/dist/plugin/types.js.map +1 -0
  191. package/dist/types/index.d.ts +191 -0
  192. package/dist/types/index.d.ts.map +1 -0
  193. package/dist/types/index.js +95 -0
  194. package/dist/types/index.js.map +1 -0
  195. package/dist/units/index.d.ts +64 -0
  196. package/dist/units/index.d.ts.map +1 -0
  197. package/dist/units/index.js +98 -0
  198. package/dist/units/index.js.map +1 -0
  199. package/docs/architecture.md +90 -0
  200. package/docs/components.md +569 -0
  201. package/docs/contributing.md +78 -0
  202. package/docs/fallback.md +174 -0
  203. package/docs/lens-pdf-viewer.md +128 -0
  204. package/docs/licensing.md +78 -0
  205. package/docs/measurement-units.md +87 -0
  206. package/docs/plugins.md +256 -0
  207. package/docs/security.md +69 -0
  208. package/docs/server.md +212 -0
  209. package/docs/services.md +210 -0
  210. package/docs/share-links.md +111 -0
  211. package/docs/theming.md +164 -0
  212. package/docs/validation.md +83 -0
  213. package/package.json +139 -0
package/README.md ADDED
@@ -0,0 +1,344 @@
1
+ ---
2
+ title: "Overview"
3
+ description: "Host-agnostic OSS PDF viewer core for React 19. A plugin-driven canvas viewer with overlay, panel, and toolbar slots. AGPL-3.0-or-later."
4
+ group: "Getting started"
5
+ order: 1
6
+ slug: "overview"
7
+ ---
8
+
9
+ # LensPDF
10
+
11
+ [![ci](https://github.com/Printwithsynergy/lens-pdf/actions/workflows/ci.yml/badge.svg)](https://github.com/Printwithsynergy/lens-pdf/actions/workflows/ci.yml)
12
+ [![license](https://img.shields.io/badge/license-AGPL--3.0--or--later-blue.svg)](./LICENSE)
13
+ [![react](https://img.shields.io/badge/react-19-61dafb.svg?logo=react&logoColor=white)](https://react.dev/)
14
+
15
+ OSS PDF viewer core. A plugin-driven canvas viewer with overlay, panel, and
16
+ toolbar slots, built around React 19. Host-agnostic: the viewer never
17
+ imports a SaaS, never hardcodes a backend route, and self-hides any tool
18
+ whose backing service the host hasn't wired. AGPL-3.0-or-later.
19
+
20
+ ## Install
21
+
22
+ LensPDF is published to the public **npm registry** under the
23
+ `@printwithsynergy` scope.
24
+
25
+ ```sh
26
+ # stable
27
+ npm install @printwithsynergy/lens-pdf
28
+
29
+ # pre-release (current)
30
+ npm install @printwithsynergy/lens-pdf@beta
31
+ ```
32
+
33
+ Peer dependencies you provide in your host app:
34
+
35
+ ```sh
36
+ npm install react react-dom
37
+ # Optional — only if you mount AnnotationCanvas / AnnotationThread:
38
+ npm install fabric
39
+ # Optional — only if you pass a `codex` client for Ghostscript-accurate
40
+ # separations / TAC / layers:
41
+ npm install @printwithsynergy/codex-client
42
+ ```
43
+
44
+ Requires `react@^19` and `react-dom@^19`. `fabric@^7` is an optional peer
45
+ used by the annotation components. `@printwithsynergy/codex-client@^1.8.1`
46
+ is an optional peer used by the codex accuracy overlay — hosts that
47
+ never pass the `codex` prop don't need to install it. `pdfjs-dist@^4`
48
+ is a regular dependency — it comes along automatically and powers the
49
+ `createBrowserViewerServices` factory exposed at `/browser`. The package
50
+ ships ESM only.
51
+
52
+ ## Quick start — pick your tier
53
+
54
+ LensPDF ships five integration levels. Start with Tier 1 and drop
55
+ down only when you need more control.
56
+
57
+ ### Tier 1 — Drop-in production viewer (~3 lines)
58
+
59
+ `<LensPDF>` is the recommended single-component entry point. One
60
+ mount, every viewer-only feature wired to pdf.js out of the box:
61
+
62
+ - **Page raster** with a multi-DPI tile cache so zoom never
63
+ degrades the image.
64
+ - **Color picker** — RGB readout plus a per-ink breakdown (CMYK
65
+ + any spot inks the PDF declares).
66
+ - **Densitometer** — per-channel coverage and TAC limit.
67
+ - **TAC heatmap** — process CMYK plus every detected spot ink
68
+ summed and visualised.
69
+ - **Per-ink separations** — toggle CMYK and any spot plates
70
+ on / off (defaults to all-on like Output Preview).
71
+ - **Layers** — OCG list with per-layer visibility.
72
+ - **Annotation toolbar / canvas / thread** — pen, arrow, rect,
73
+ ellipse, text, highlight, sticky note, all in-memory.
74
+ - **Mobile** — tools collapse into a left-anchored slide-in
75
+ drawer; readouts swap to bottom sheets so they stay legible.
76
+
77
+ ```tsx
78
+ import { LensPDF } from "@printwithsynergy/lens-pdf";
79
+ import pdfWorkerSrc from "pdfjs-dist/build/pdf.worker.mjs?url";
80
+
81
+ export function ProofPage() {
82
+ return <LensPDF pdfUrl="/proofs/abc.pdf" workerSrc={pdfWorkerSrc} />;
83
+ }
84
+ ```
85
+
86
+ Hosts with a preflight engine plug findings + dieline + box overlays
87
+ in directly:
88
+
89
+ ```tsx
90
+ <LensPDF
91
+ pdfUrl="/proofs/abc.pdf"
92
+ workerSrc={pdfWorkerSrc}
93
+ items={findings} // OverlayItem[] — error / warning / advisory bboxes
94
+ selectedItem={selected}
95
+ onItemSelect={setSelected}
96
+ dieline={dielineForCurrentPage}
97
+ showBoxOverlays // trim / bleed / crop popovers
98
+ cropToTrim // clip the canvas to TrimBox
99
+ tools={["color-picker", "densitometer", "annotate", "tac-heatmap"]}
100
+ onPageChange={setCurrentPage}
101
+ tokens={{ accent: "#e50c6a" }}
102
+ brand="MyApp"
103
+ brandLogoUrl="/logo.svg"
104
+ />
105
+ ```
106
+
107
+ No backend required for the viewer side. Server-only features (HTML /
108
+ PDF report exports, ICC-correct preflight separations, server-
109
+ persisted annotations) self-hide because their dedicated services are
110
+ intentionally `markUnwired`. Hosts with a backend pass `services` to
111
+ override the in-browser ones.
112
+
113
+ ### Tier 1b — Demo / showcase viewer
114
+
115
+ Same component, with an upload bar + drag-drop + URL paste — useful
116
+ for marketing pages and internal sandboxes where users bring their
117
+ own files.
118
+
119
+ ```tsx
120
+ import { LensPDFDemo } from "@printwithsynergy/lens-pdf";
121
+
122
+ export function DemoPage() {
123
+ return <LensPDFDemo brand="MyApp" brandLogoUrl="/logo.svg" />;
124
+ }
125
+ ```
126
+
127
+ ### Tier 2 — One-liner viewer (~5 lines)
128
+
129
+ `<LensPDFViewer>` auto-discovers pages, layers, dimensions. Ships
130
+ a responsive toolbar with zoom, layers, color picker, and measure.
131
+
132
+ ```tsx
133
+ import { LensPDFViewer } from "@printwithsynergy/lens-pdf/components";
134
+
135
+ export function MyViewer() {
136
+ return <LensPDFViewer pdfUrl="https://cdn.example.com/proof.pdf" />;
137
+ }
138
+ ```
139
+
140
+ Slot props (`header`, `sidebar`, `footer`) let you replace regions
141
+ without losing the rest of the viewer:
142
+
143
+ ```tsx
144
+ <LensPDFViewer
145
+ pdfUrl={url}
146
+ header={(state) => <MyToolbar zoom={state.zoom} setZoom={state.setZoom} />}
147
+ footer={<p>Custom footer</p>}
148
+ />
149
+ ```
150
+
151
+ ### Tier 3 — Hook + Provider (~20 lines)
152
+
153
+ `useLensPDF()` manages all state; `<LensPDFProvider>` mounts both
154
+ contexts. Build any layout you want on top.
155
+
156
+ ```tsx
157
+ import { useLensPDF, LensPDFProvider } from "@printwithsynergy/lens-pdf/host";
158
+ import { PageCanvas } from "@printwithsynergy/lens-pdf/components";
159
+
160
+ export function CustomViewer({ url }: { url: string }) {
161
+ const viewer = useLensPDF(url, { tokens: { accent: "#e50c6a" } });
162
+
163
+ return (
164
+ <LensPDFProvider value={viewer}>
165
+ <PageCanvas jobId="demo" page={viewer.currentPageInfo} zoom={viewer.zoom} items={[]} selectedItem={null} onItemClick={() => {}} />
166
+ </LensPDFProvider>
167
+ );
168
+ }
169
+ ```
170
+
171
+ ### Tier 4 — Full custom composition
172
+
173
+ Wire `ViewerHostContext` + `ViewerServicesContext` yourself. Every
174
+ component (`PageCanvas`, `LayerPanel`, `MeasureTool`, etc.) is
175
+ exported and unchanged.
176
+
177
+ ### Shareable links
178
+
179
+ Generate URLs that open the viewer with a specific PDF and settings:
180
+
181
+ ```ts
182
+ import { generateShareLink, parseShareParams } from "@printwithsynergy/lens-pdf/host";
183
+
184
+ const link = generateShareLink({
185
+ baseUrl: "https://lenspdf.com/demo",
186
+ pdfUrl: "https://cdn.example.com/proof.pdf",
187
+ fullscreen: true,
188
+ zoom: 150,
189
+ });
190
+
191
+ // On the demo page:
192
+ const params = parseShareParams(new URLSearchParams(window.location.search));
193
+ // → { pdfUrl: "https://...", fullscreen: true, zoom: 150 }
194
+ ```
195
+
196
+ ### PDF validation
197
+
198
+ Client-side checks (magic bytes, MIME, size) are built in:
199
+
200
+ ```ts
201
+ import { validatePdfFile, validatePdfUrl } from "@printwithsynergy/lens-pdf/host";
202
+
203
+ const result = await validatePdfFile(file); // { valid: true } or { valid: false, error: "..." }
204
+ ```
205
+
206
+ ### Browser-only services (full feature surface, no backend)
207
+
208
+ `createBrowserViewerServices` returns a complete `ViewerServices`
209
+ backed by pdf.js — every viewer-only feature works on any PDF the
210
+ browser can fetch:
211
+
212
+ ```tsx
213
+ import { createBrowserViewerServices } from "@printwithsynergy/lens-pdf/browser";
214
+ import { ViewerServicesContext, ViewerHostContext } from "@printwithsynergy/lens-pdf/host";
215
+
216
+ const services = createBrowserViewerServices({ pdfUrl: "/proof.pdf" });
217
+
218
+ <ViewerHostContext.Provider value={{ apiBase: "", jobApiBase: "", readOnly: false }}>
219
+ <ViewerServicesContext.Provider value={services}>
220
+ <PageCanvas ... />
221
+ <SeparationCanvas ... />
222
+ <TACHeatmapOverlay ... />
223
+ {/* etc. */}
224
+ </ViewerServicesContext.Provider>
225
+ </ViewerHostContext.Provider>;
226
+
227
+ services.dispose(); // free blob URLs / pdf.js doc on unmount
228
+ ```
229
+
230
+ CMYK / TAC are RGB-derived approximations when no backend is wired.
231
+ Spot inks are detected by scanning raw PDF bytes for `/Separation`
232
+ and `/DeviceN` colour spaces; each detected spot's coverage is
233
+ estimated from its alternate-RGB direction. Good for visual
234
+ showcase and casual review, **not** press-grade. For ICC-correct
235
+ readings deploy the optional reference server below and pass its
236
+ `services` overrides — the components automatically swap from the
237
+ browser approximation to ICC-derived data with no markup change.
238
+
239
+ ## Findings + dieline (0.3.0-beta.71 +)
240
+
241
+ Two built-in components for adapter authors (lint-pdf, callas
242
+ pdfToolbox, PitStop, Acrobat, custom rule engines) mapping their
243
+ preflight findings into Lens overlays:
244
+
245
+ - **`FindingsSidebar`** — vertical sidebar that splits items into
246
+ collapsible **Located in viewer** (clickable, draws boxes/numbers
247
+ on the canvas) and **Informational** (no bbox, surfaced as static
248
+ rows). Severity-filter pills along the top.
249
+ - **`DielineInfoPanel`** — info card showing source / spot name /
250
+ confidence + per-region size (mm + inches) from a
251
+ `DielineResult`. Pairs with the canvas-side dieline bbox that
252
+ `BoxOverlay` now draws automatically when the same prop is
253
+ passed to `<LensPDF dieline={...}>`.
254
+
255
+ Plus two helpers exported from `@printwithsynergy/lens-pdf/plugin`:
256
+
257
+ - **`hasViewerLocation(item)`** — true when the item has a bbox /
258
+ point / regions. Same predicate the canvas uses internally.
259
+ - **`splitFindingsByLocation(items)`** — returns
260
+ `{located, informational}` preserving order in each bucket.
261
+
262
+ ```tsx
263
+ import {
264
+ LensPDF,
265
+ FindingsSidebar,
266
+ DielineInfoPanel,
267
+ } from "@printwithsynergy/lens-pdf";
268
+
269
+ <div className="flex h-full w-full">
270
+ <FindingsSidebar items={overlayItems} onSelect={setSelected} />
271
+ <LensPDF
272
+ items={overlayItems}
273
+ selectedItem={selected}
274
+ onItemSelect={setSelected}
275
+ dieline={dielineResult}
276
+ />
277
+ <DielineInfoPanel dieline={dielineResult} />
278
+ </div>
279
+ ```
280
+
281
+ `FindingsSidebar` + `DielineInfoPanel` are no-ops when their data
282
+ prop is empty/null so hosts mount them unconditionally — they only
283
+ render once real data arrives. Theming honours Lens's brand-* /
284
+ slate-* tokens.
285
+
286
+ ## Demo
287
+
288
+ Want to see the hide-on-unwired contract in action without setting up your own
289
+ host? `demo/` is a tiny Vite app that flips between empty / pdf.js-fallback /
290
+ fully-mocked contexts:
291
+
292
+ ```sh
293
+ cd demo && npm install && npm run dev
294
+ ```
295
+
296
+ See [demo/README.md](./demo/README.md) for the smoke-check checklist.
297
+
298
+ ## Optional reference server
299
+
300
+ For **press-grade ICC-correct** ink separations, densitometer readings,
301
+ and TAC heatmap (the browser services use an RGB→CMYK approximation —
302
+ fine for showcase, not for prepress sign-off), deploy the small
303
+ Node + Ghostscript service in [`server/`](./server). Wire its
304
+ endpoints into your `ViewerServices` and the corresponding components
305
+ swap from the browser approximation to ICC-derived data.
306
+
307
+ ```sh
308
+ cd server && docker build -t lens-pdf-server .
309
+ docker run -p 3000:3000 -v lens-jobs:/var/lib/lens-pdf/jobs lens-pdf-server
310
+ ```
311
+
312
+ See [docs/server.md](./docs/server.md) for the HTTP contract,
313
+ deployment notes, and security caveats.
314
+
315
+ ## Documentation
316
+
317
+ | Topic | Doc |
318
+ | --- | --- |
319
+ | The one-line `<LensPDFViewer>` composition | [docs/lens-pdf-viewer.md](./docs/lens-pdf-viewer.md) |
320
+ | How the contexts, components, and plugins fit together | [docs/architecture.md](./docs/architecture.md) |
321
+ | Wiring `ViewerServices` (page images, layers, separations, TAC, color, densitometer, annotations, reports) | [docs/services.md](./docs/services.md) |
322
+ | Capability detection, debug logging, and the in-browser PDF fallback | [docs/fallback.md](./docs/fallback.md) |
323
+ | Optional Node + Ghostscript backend for preflight-grade tools | [docs/server.md](./docs/server.md) |
324
+ | Per-component props and usage | [docs/components.md](./docs/components.md) |
325
+ | Plugin slots, registration, and the `replaces` mechanism | [docs/plugins.md](./docs/plugins.md) |
326
+ | Built-in `MeasurementUnit`s + custom-unit Protocol | [docs/measurement-units.md](./docs/measurement-units.md) |
327
+ | Theme tokens, i18n, telemetry, read-only mode | [docs/theming.md](./docs/theming.md) |
328
+ | Shareable viewer links (`generateShareLink`, `parseShareParams`) | [docs/share-links.md](./docs/share-links.md) |
329
+ | Client-side PDF validation (`validatePdfFile`, `validatePdfUrl`) | [docs/validation.md](./docs/validation.md) |
330
+ | Boundary rule, provenance, contributing | [docs/contributing.md](./docs/contributing.md) |
331
+
332
+ ## Community
333
+
334
+ - [CHANGELOG](./CHANGELOG.md) — release notes (Keep-a-Changelog format).
335
+ - [CONTRIBUTING](./CONTRIBUTING.md) — quick-start; the full guide is in [docs/contributing.md](./docs/contributing.md).
336
+ - [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md) — Contributor Covenant 2.1.
337
+ - [SECURITY](./SECURITY.md) — vulnerability disclosure process. **Don't open public issues for security problems.**
338
+
339
+ ## License
340
+
341
+ LensPDF is licensed under the GNU Affero General Public License v3.0 or
342
+ later (AGPL-3.0-or-later). See [`LICENSE`](./LICENSE) for the full text.
343
+
344
+ Copyright (C) 2026 Think Neverland LLC.
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Codex accuracy overlay for `<LensPDFDemo>`.
3
+ *
4
+ * When a host passes a `codex` client, `LensPDFDemo` fires
5
+ * `extractStream` in the background. This module wraps the codex
6
+ * render APIs (renderSeparations, renderHeatmap, renderLayer) into
7
+ * the `ViewerServices` slot interface so the viewer can swap in
8
+ * Ghostscript-accurate renders silently once they arrive.
9
+ *
10
+ * This module has **no import of `@printwithsynergy/codex-client`**.
11
+ * It defines a minimal structural interface — any object whose shape
12
+ * matches `MinimalCodexClient` (including `HttpClient` from
13
+ * `@printwithsynergy/codex-client`) satisfies it.
14
+ *
15
+ * @public
16
+ */
17
+ import type { SeparationService, LayerService, TACHeatmapService } from "../plugin/services";
18
+ import type { DetectedInk } from "./index";
19
+ /**
20
+ * Minimal subset of `@printwithsynergy/codex-client`'s `HttpClient`
21
+ * that `LensPDFDemo` uses for the accuracy overlay. Any object
22
+ * implementing this interface (including `HttpClient`) is accepted.
23
+ *
24
+ * @public
25
+ */
26
+ export interface MinimalCodexClient {
27
+ extractStream(pdf: ArrayBuffer | Uint8Array, callbacks: {
28
+ granular?: boolean;
29
+ onColorWorld?: (data: Record<string, unknown>) => void;
30
+ onOcgs?: (data: Record<string, unknown>) => void;
31
+ onPhase2?: (doc: {
32
+ pdf_sha256: string;
33
+ [key: string]: unknown;
34
+ }) => void;
35
+ }): Promise<{
36
+ pdf_sha256: string;
37
+ [key: string]: unknown;
38
+ }>;
39
+ renderSeparations(pdf: {
40
+ sha256: string;
41
+ }, opts?: {
42
+ page?: number;
43
+ dpi?: number;
44
+ }): Promise<{
45
+ channels: Array<{
46
+ name: string;
47
+ type: string;
48
+ png_b64: string;
49
+ }>;
50
+ }>;
51
+ renderHeatmap(pdf: {
52
+ sha256: string;
53
+ }, opts?: {
54
+ page?: number;
55
+ dpi?: number;
56
+ tacLimit?: number;
57
+ }): Promise<{
58
+ png: Uint8Array;
59
+ }>;
60
+ renderLayer(pdf: {
61
+ sha256: string;
62
+ }, opts: {
63
+ page?: number;
64
+ layerIndex: number;
65
+ allLayerIndices: number[];
66
+ dpi?: number;
67
+ }): Promise<Uint8Array>;
68
+ }
69
+ /**
70
+ * Extract a `DetectedInk[]` from the `color_world` SSE event payload.
71
+ * Returns the 4 CMYK process channels plus any spot colorants the
72
+ * PDF declares (accurate — from pikepdf, not regex scanning).
73
+ *
74
+ * @public
75
+ */
76
+ export declare function extractInksFromColorWorld(colorWorld: Record<string, unknown>): DetectedInk[];
77
+ /**
78
+ * Extract a layer list from the `ocgs` SSE event payload.
79
+ *
80
+ * @public
81
+ */
82
+ export declare function extractLayersFromOcgs(ocgs: Record<string, unknown>): Array<{
83
+ name: string;
84
+ ocg_index: number;
85
+ default_on: boolean;
86
+ }>;
87
+ export interface CodexOverlayServices {
88
+ separations: SeparationService;
89
+ tacHeatmap: TACHeatmapService;
90
+ layers: LayerService;
91
+ subscribe(listener: () => void): () => void;
92
+ dispose(): void;
93
+ }
94
+ /**
95
+ * Build `separations`, `tacHeatmap`, and `layers` service slots backed
96
+ * by the codex render APIs. Lazy: each page's renders are fetched the
97
+ * first time they're requested, then cached as blob URLs.
98
+ *
99
+ * Hosts swap these into `ViewerServices` after `phase2_complete` fires
100
+ * so pdfjs approximations are replaced by Ghostscript renders.
101
+ *
102
+ * @public
103
+ */
104
+ export declare function createCodexOverlayServices(client: MinimalCodexClient, sha256: string, tacLimit: number, layerData: ReadonlyArray<{
105
+ name: string;
106
+ ocg_index: number;
107
+ default_on: boolean;
108
+ }>): CodexOverlayServices;
109
+ //# sourceMappingURL=codexOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexOverlay.d.ts","sourceRoot":"","sources":["../../browser/codexOverlay.ts"],"names":[],"mappings":"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"}