@embedpdf/angular 3.0.0-next.0

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.
@@ -0,0 +1,502 @@
1
+ import { createKernel, docInfoListEquals } from '@embedpdf/core';
2
+ export * from '@embedpdf/core';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, PLATFORM_ID, signal, computed, Injectable, makeEnvironmentProviders, InjectionToken, input, forwardRef, Directive, ViewContainerRef, TemplateRef, effect, ChangeDetectionStrategy, Component } from '@angular/core';
5
+ import { isPlatformBrowser } from '@angular/common';
6
+
7
+ /**
8
+ * The kernel host — one service owns the kernel; ONE tick signal bridges the
9
+ * kernel's single change stream into Angular's signal graph. Everything else in
10
+ * this adapter is `computed()` over it (`value()` is Angular's `useKernelValue`).
11
+ *
12
+ * Two hosting modes share this class:
13
+ * component-hosted `<epdf-viewer [engine] [plugins]>` (framework parity)
14
+ * provider-hosted `provideEmbedPdf({...})` at route/app level
15
+ *
16
+ * CONSTRUCTION RULE (library law): nothing may read `host.kernel` while a
17
+ * component is being CONSTRUCTED. Component-hosted configs resolve their inputs
18
+ * lazily, so the kernel materializes on first real read (a template binding, an
19
+ * effect) — after inputs are set. Every inject* primitive returns signals or
20
+ * lazy methods and therefore respects this for free; only the raw
21
+ * `injectKernel()` escape hatch can violate it (its doc says so).
22
+ *
23
+ * SSR CONTRACT: the EmbedPDF subtree is browser-only. On the server the host
24
+ * never boots and any `kernel` read throws — wrap the viewer region in `@defer`
25
+ * (which renders its placeholder on the server) or a platform-guarded `@if`.
26
+ */
27
+ class EpdfKernelHost {
28
+ browser = isPlatformBrowser(inject(PLATFORM_ID));
29
+ config = null;
30
+ _kernel = null;
31
+ /** The engine backing the kernel, and whether WE created it (a recipe) and
32
+ * therefore must destroy it. A borrowed instance is left untouched. */
33
+ _engine = null;
34
+ ownsEngine = false;
35
+ unsubscribe = null;
36
+ initialDocuments;
37
+ booted = false;
38
+ destroyed = false;
39
+ /** Bumped on every kernel notification — THE bridge from kernel-world to signals. */
40
+ tick = signal(0, ...(ngDevMode ? [{ debugName: "tick" }] : []));
41
+ /** Boot lifecycle. `ready`/`error` are derived sugar over it. */
42
+ status = signal('starting', ...(ngDevMode ? [{ debugName: "status" }] : []));
43
+ /** The STARTUP failure, if any. Per-document open failures are tab state
44
+ * (`DocInfo.status === 'error'`), not host state. */
45
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
46
+ /** True once `kernel.start()` resolved — which never touches the engine, so
47
+ * the shell (and every workspace capability: i18n, view-manager, …) is alive
48
+ * while WASM compiles or the transport connects. Workspace chrome may render
49
+ * before this; gate on it (or on the document gate) where it matters. */
50
+ ready = computed(() => this.status() === 'ready', ...(ngDevMode ? [{ debugName: "ready" }] : []));
51
+ /** Register the (deferred) config. Called exactly once, by `EpdfViewer`'s
52
+ * constructor or `provideEmbedPdf`'s factory. */
53
+ connect(config) {
54
+ if (this.config || this._kernel) {
55
+ throw new Error('[embedpdf] kernel already configured for this injector');
56
+ }
57
+ this.config = config;
58
+ }
59
+ /** The kernel — materialized on first read (see the construction rule above). */
60
+ get kernel() {
61
+ if (!this._kernel) {
62
+ if (!this.browser) {
63
+ throw new Error('[embedpdf] the viewer does not render on the server — wrap the EmbedPDF subtree in @defer (its placeholder renders during SSR) or a browser-only @if');
64
+ }
65
+ if (!this.config) {
66
+ throw new Error('[embedpdf] no kernel: wrap this subtree in <epdf-viewer> or add provideEmbedPdf(...) to your providers');
67
+ }
68
+ const { engine, plugins, initialDocuments } = this.config();
69
+ // A thunk is host-owned: call it now, destroy on teardown. An instance is
70
+ // borrowed and left untouched. Either way construction is synchronous and
71
+ // inert (engines boot lazily on first use).
72
+ this.ownsEngine = typeof engine === 'function';
73
+ this._engine = this.ownsEngine ? engine() : engine;
74
+ try {
75
+ this._kernel = createKernel({ engine: this._engine, plugins });
76
+ }
77
+ catch (error) {
78
+ // ngOnDestroy() only tears down via `_kernel`, which stays null on this
79
+ // path — so an owned engine must be destroyed HERE or it leaks.
80
+ if (this.ownsEngine)
81
+ void this._engine.destroy();
82
+ this._engine = null;
83
+ this.ownsEngine = false;
84
+ throw error;
85
+ }
86
+ // Warm up only once the kernel exists (a plugin-planning throw must not
87
+ // start a boot we'd immediately have to unwind) — `warmup()` overlaps the
88
+ // WASM/transport boot with the rest of initialization.
89
+ this._engine.warmup?.();
90
+ this.initialDocuments = initialDocuments;
91
+ this.unsubscribe = this._kernel.subscribe(() => this.tick.update((n) => n + 1));
92
+ }
93
+ return this._kernel;
94
+ }
95
+ /** Start the kernel and open initial documents in the background. Idempotent;
96
+ * a no-op on the server and after destroy. */
97
+ boot() {
98
+ if (this.booted || this.destroyed || !this.browser)
99
+ return;
100
+ this.booted = true;
101
+ const kernel = this.kernel;
102
+ void (async () => {
103
+ try {
104
+ await kernel.start();
105
+ }
106
+ catch (err) {
107
+ if (!this.destroyed) {
108
+ this.error.set(err);
109
+ this.status.set('error');
110
+ }
111
+ return;
112
+ }
113
+ if (this.destroyed)
114
+ return;
115
+ this.status.set('ready');
116
+ // Kernel-owned boot policy: all tabs appear immediately in array order;
117
+ // the `active` entry (else the first) is selected; per-document
118
+ // failures surface as that tab's `error`/`locked` status (this host's
119
+ // `error` signal reports only startup failures).
120
+ kernel.documents.openAll(this.initialDocuments ?? []);
121
+ })();
122
+ }
123
+ /** Read a value derived from the kernel, cached by equality — Angular's
124
+ * `useKernelValue`. The selector re-runs per kernel notification (cheap);
125
+ * `equal` decides whether dependents ever see it. */
126
+ value(select, equal = Object.is) {
127
+ return computed(() => {
128
+ this.tick();
129
+ return select(this.kernel);
130
+ }, { equal });
131
+ }
132
+ ngOnDestroy() {
133
+ if (this.destroyed)
134
+ return;
135
+ this.destroyed = true;
136
+ this.unsubscribe?.();
137
+ // destroy() owns the full teardown now: it joins an in-flight start, closes
138
+ // every document (engine handles included), and unwinds workspace plugins.
139
+ // Async + idempotent, so fire-and-forget is safe in a sync ngOnDestroy.
140
+ // Then destroy the engine IF we own it (a thunk) — kernel first so handles
141
+ // close before the engine goes; `engine.destroy()` joins any in-flight
142
+ // boot or no-ops if it never started.
143
+ if (this._kernel) {
144
+ const engine = this._engine;
145
+ const owns = this.ownsEngine;
146
+ void this._kernel.destroy().then(() => {
147
+ if (owns && engine)
148
+ void engine.destroy();
149
+ });
150
+ }
151
+ }
152
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfKernelHost, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
153
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfKernelHost });
154
+ }
155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfKernelHost, decorators: [{
156
+ type: Injectable
157
+ }] });
158
+ /**
159
+ * Host the kernel in an environment injector (route or application providers).
160
+ * The kernel's lifetime is the injector's — a route-level workspace tears down
161
+ * when the route does. Unlocks chrome OUTSIDE any viewer subtree: a toolbar in
162
+ * the app header and the stage in the main outlet share this one kernel.
163
+ */
164
+ function provideEmbedPdf(config) {
165
+ return makeEnvironmentProviders([
166
+ {
167
+ provide: EpdfKernelHost,
168
+ useFactory: () => {
169
+ const host = new EpdfKernelHost();
170
+ host.connect(() => config);
171
+ host.boot();
172
+ return host;
173
+ },
174
+ },
175
+ ]);
176
+ }
177
+
178
+ /**
179
+ * DI tokens shared by the runtime's primitives and directives — split out so
180
+ * `inject.ts` (consumers) and `scope.ts` (providers) never import each other.
181
+ */
182
+ const EPDF_DOCUMENT_SCOPE = new InjectionToken('EPDF_DOCUMENT_SCOPE');
183
+
184
+ /**
185
+ * The inject* primitives — Angular's spelling of the React runtime hooks
186
+ * (`use*` → `inject*`, plain values → signals, same names otherwise).
187
+ *
188
+ * All of them must run in an injection context (a constructor / field
189
+ * initializer, like `inject()` itself). None of them read `host.kernel` during
190
+ * construction — they return signals or lazy methods, so they are safe in
191
+ * component-hosted mode where the kernel materializes after construction.
192
+ */
193
+ const shallowArray = (a, b) => a === b || (a.length === b.length && a.every((x, i) => x === b[i]));
194
+ function injectKernelHost() {
195
+ const host = inject(EpdfKernelHost, { optional: true });
196
+ if (!host) {
197
+ throw new Error('[embedpdf] no kernel: wrap this subtree in <epdf-viewer> or add provideEmbedPdf(...) to your providers');
198
+ }
199
+ return host;
200
+ }
201
+ /** The raw kernel — materializes it immediately. Do NOT call while a component
202
+ * is being constructed in component-hosted mode (inputs are not set yet);
203
+ * prefer the signal-returning primitives, which defer the first kernel read. */
204
+ function injectKernel() {
205
+ return injectKernelHost().kernel;
206
+ }
207
+ /** Read a value derived from the kernel, cached by equality — `useKernelValue`. */
208
+ function injectKernelValue(select, equal) {
209
+ return injectKernelHost().value(select, equal);
210
+ }
211
+ function injectActiveDocumentId() {
212
+ return injectKernelValue((k) => k.documents.activeId());
213
+ }
214
+ /** The document id for this injector subtree: the nearest `[epdfDocumentScope]`,
215
+ * else the active document. */
216
+ function injectDocumentId() {
217
+ const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });
218
+ const active = injectActiveDocumentId();
219
+ return computed(() => scope?.id() ?? active());
220
+ }
221
+ /**
222
+ * Resolve a capability against a REACTIVE token — for components that take the
223
+ * token as an input (`injectCapability` is the fixed-token sugar). Resolution
224
+ * is a REACTIVE read (`tryCapability` through the kernel's one change
225
+ * stream), not a computed over the document id — under the request-time
226
+ * lifecycle a document can become resolvable while its id stays the same, so
227
+ * any id-keyed cache goes stale; subscribing makes staleness structurally
228
+ * impossible. Fail-fast like React's `useCapability`: while unresolvable,
229
+ * this re-runs the strict resolver so the kernel's truthful reason (`no
230
+ * capability` / `no document` / `document is loading|locked`) is what throws.
231
+ */
232
+ function injectCapabilityFor(token) {
233
+ const host = injectKernelHost();
234
+ const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });
235
+ const cap = host.value((k) => k.tryCapability(token(), scope?.id() ?? undefined));
236
+ return computed(() => cap() ?? host.kernel.capability(token(), scope?.id() ?? undefined));
237
+ }
238
+ function injectCapability(token) {
239
+ return injectCapabilityFor(() => token);
240
+ }
241
+ /** Like `injectCapabilityFor`, but null while the token can't resolve (no
242
+ * plugin, no document, or a document that isn't ready yet). */
243
+ function injectOptionalCapabilityFor(token) {
244
+ const host = injectKernelHost();
245
+ const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });
246
+ return host.value((k) => k.tryCapability(token(), scope?.id() ?? undefined));
247
+ }
248
+ function injectOptionalCapability(token) {
249
+ return injectOptionalCapabilityFor(() => token);
250
+ }
251
+ /** Subscribe to a selector over a (document-resolved) capability. */
252
+ function injectSelectorFor(token, select, equal) {
253
+ const host = injectKernelHost();
254
+ const cap = injectCapabilityFor(token);
255
+ return host.value(() => select(cap()), equal);
256
+ }
257
+ function injectSelector(token, select, equal) {
258
+ return injectSelectorFor(() => token, select, equal);
259
+ }
260
+ /**
261
+ * Null-safe `injectSelector`: `fallback` whenever the token can't resolve — no
262
+ * provider, or a document-scoped token with no document. For chrome that stays
263
+ * mounted across the empty-workspace state (a zoom readout, a mode band).
264
+ * `injectSelector` stays strict (fail-fast) for code that KNOWS a document
265
+ * exists — e.g. anything behind the document gate.
266
+ *
267
+ * The `select` guard also swallows reads through a capability whose document
268
+ * closed between the store notification and this read — that teardown race
269
+ * resolves to `fallback` for one frame, then recomputes against the new state.
270
+ */
271
+ function injectOptionalSelectorFor(token, select, fallback, equal) {
272
+ const host = injectKernelHost();
273
+ const cap = injectOptionalCapabilityFor(token);
274
+ return host.value(() => {
275
+ const c = cap();
276
+ if (c === null)
277
+ return fallback;
278
+ try {
279
+ return select(c);
280
+ }
281
+ catch {
282
+ return fallback;
283
+ }
284
+ }, equal);
285
+ }
286
+ function injectOptionalSelector(token, select, fallback, equal) {
287
+ return injectOptionalSelectorFor(() => token, select, fallback, equal);
288
+ }
289
+ function injectDocuments() {
290
+ const host = injectKernelHost();
291
+ return {
292
+ docs: host.value((k) => k.documents.list(), docInfoListEquals),
293
+ activeId: host.value((k) => k.documents.activeId()),
294
+ open: (input, options) => host.kernel.documents.open(input, options),
295
+ unlock: (id, input) => host.kernel.documents.unlock(id, input),
296
+ close: (id) => host.kernel.documents.close(id),
297
+ setActive: (id) => host.kernel.documents.setActive(id),
298
+ move: (id, toIndex) => host.kernel.documents.move(id, toIndex),
299
+ swap: (a, b) => host.kernel.documents.swap(a, b),
300
+ download: (id, opts) => host.kernel.documents.download(id, opts),
301
+ downloadLayer: (id) => host.kernel.documents.downloadLayer(id),
302
+ };
303
+ }
304
+
305
+ /**
306
+ * Document scoping — hierarchical DI is Angular's native React-context.
307
+ *
308
+ * `[epdfDocumentScope]` binds a subtree to a SPECIFIC document (panes,
309
+ * comparison); `*epdfDocumentGate` renders a subtree only WHILE it has one.
310
+ * The gate is a structural directive on purpose: a template genuinely defers
311
+ * creation, which a conditional `<ng-content>` slot cannot (Angular
312
+ * instantiates projected content eagerly). Document-scoped UI — the Stage,
313
+ * zoom/page controls, panels — belongs behind it (or behind the app's own
314
+ * `@if (documentId())`); workspace chrome lives outside it.
315
+ */
316
+ class EpdfDocumentScope {
317
+ id = input.required(...(ngDevMode ? [{ debugName: "id", alias: 'epdfDocumentScope' }] : [{ alias: 'epdfDocumentScope' }]));
318
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfDocumentScope, deps: [], target: i0.ɵɵFactoryTarget.Directive });
319
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfDocumentScope, isStandalone: true, selector: "[epdfDocumentScope]", inputs: { id: { classPropertyName: "id", publicName: "epdfDocumentScope", isSignal: true, isRequired: true, transformFunction: null } }, providers: [{ provide: EPDF_DOCUMENT_SCOPE, useExisting: forwardRef(() => EpdfDocumentScope) }], ngImport: i0 });
320
+ }
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfDocumentScope, decorators: [{
322
+ type: Directive,
323
+ args: [{
324
+ selector: '[epdfDocumentScope]',
325
+ standalone: true,
326
+ providers: [{ provide: EPDF_DOCUMENT_SCOPE, useExisting: forwardRef(() => EpdfDocumentScope) }],
327
+ }]
328
+ }] });
329
+ /**
330
+ * Render the host template only while this subtree has a document — the
331
+ * structural way to say "this UI is defined over a document". Sibling of
332
+ * `[epdfDocumentScope]`, which picks WHICH document; this one handles WHETHER.
333
+ *
334
+ * <section *epdfDocumentGate="; fallback: empty">…document UI…</section>
335
+ * <ng-template #empty>Drop a PDF to get started</ng-template>
336
+ *
337
+ * The subtree stays mounted across a CHANGE of document (active-tab switch) —
338
+ * only the has-a-document boolean creates/destroys it.
339
+ */
340
+ class EpdfDocumentGate {
341
+ /** Shown while this subtree has NO document (empty workspace, docs still opening). */
342
+ fallback = input(null, ...(ngDevMode ? [{ debugName: "fallback", alias: 'epdfDocumentGateFallback' }] : [{
343
+ alias: 'epdfDocumentGateFallback',
344
+ }]));
345
+ constructor() {
346
+ const docId = injectDocumentId();
347
+ const hasDocument = computed(() => docId() !== null, ...(ngDevMode ? [{ debugName: "hasDocument" }] : []));
348
+ const container = inject(ViewContainerRef);
349
+ const content = inject(TemplateRef);
350
+ effect(() => {
351
+ container.clear();
352
+ if (hasDocument()) {
353
+ container.createEmbeddedView(content);
354
+ }
355
+ else {
356
+ // `fallback` is only tracked while gated — swapping fallback templates
357
+ // never recreates live document UI.
358
+ const fallbackTemplate = this.fallback();
359
+ if (fallbackTemplate)
360
+ container.createEmbeddedView(fallbackTemplate);
361
+ }
362
+ });
363
+ }
364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfDocumentGate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
365
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfDocumentGate, isStandalone: true, selector: "[epdfDocumentGate]", inputs: { fallback: { classPropertyName: "fallback", publicName: "epdfDocumentGateFallback", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
366
+ }
367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfDocumentGate, decorators: [{
368
+ type: Directive,
369
+ args: [{ selector: '[epdfDocumentGate]', standalone: true }]
370
+ }], ctorParameters: () => [] });
371
+
372
+ /**
373
+ * `<epdf-viewer>` — component-hosted kernel (framework parity with React's
374
+ * `<Viewer>`). Provides `EpdfKernelHost` at its element injector, boots it, and
375
+ * projects content UNCONDITIONALLY: it is NOT a gate. Angular instantiates
376
+ * projected content eagerly whether or not a slot renders it, so a conditional
377
+ * `<ng-content>` cannot defer anything — real gating belongs to templates the
378
+ * APP owns: `@if (ready())` for boot chrome, `*epdfDocumentGate` (or
379
+ * `@if (documentId())`) for document UI.
380
+ *
381
+ * Prefer `provideEmbedPdf(...)` at route/app level when chrome lives outside
382
+ * one subtree; this component is sugar over the same host.
383
+ */
384
+ class EpdfViewer {
385
+ /** The engine, as an instance OR a thunk ({@link EngineFactory}). An
386
+ * instance is borrowed (never destroyed here); a thunk is host-owned
387
+ * (constructed then destroyed with the viewer). See EmbedPdfConfig.
388
+ * Init-only: the kernel is built once from the first values; recreate the
389
+ * viewer (e.g. with @if) to swap it. */
390
+ engine = input.required(...(ngDevMode ? [{ debugName: "engine" }] : []));
391
+ plugins = input.required(...(ngDevMode ? [{ debugName: "plugins" }] : []));
392
+ initialDocuments = input(...(ngDevMode ? [undefined, { debugName: "initialDocuments" }] : []));
393
+ /** The host this viewer provides — exposed so a template reference can read
394
+ * `viewer.host.ready()` / `.status()` without extra imports. */
395
+ host = inject(EpdfKernelHost, { self: true });
396
+ constructor() {
397
+ // Deferred config: inputs are READ on first kernel access, which happens
398
+ // after construction (a template binding or effect) — never here.
399
+ this.host.connect(() => ({
400
+ engine: this.engine(),
401
+ plugins: this.plugins(),
402
+ initialDocuments: this.initialDocuments(),
403
+ }));
404
+ }
405
+ ngOnInit() {
406
+ // Inputs are set by now; materializes the kernel and starts it (no-op on
407
+ // the server — the SSR contract lives on the host).
408
+ this.host.boot();
409
+ }
410
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfViewer, deps: [], target: i0.ɵɵFactoryTarget.Component });
411
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.2.4", type: EpdfViewer, isStandalone: true, selector: "epdf-viewer", inputs: { engine: { classPropertyName: "engine", publicName: "engine", isSignal: true, isRequired: true, transformFunction: null }, plugins: { classPropertyName: "plugins", publicName: "plugins", isSignal: true, isRequired: true, transformFunction: null }, initialDocuments: { classPropertyName: "initialDocuments", publicName: "initialDocuments", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: contents;" }, providers: [EpdfKernelHost], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
412
+ }
413
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfViewer, decorators: [{
414
+ type: Component,
415
+ args: [{
416
+ selector: 'epdf-viewer',
417
+ standalone: true,
418
+ changeDetection: ChangeDetectionStrategy.OnPush,
419
+ providers: [EpdfKernelHost],
420
+ // Layout-transparent, like React's element-less <Viewer>.
421
+ host: { style: 'display: contents;' },
422
+ template: `<ng-content />`,
423
+ }]
424
+ }], ctorParameters: () => [] });
425
+
426
+ /**
427
+ * PageContext — the seam. A layer depends ONLY on this, never on the Stage, so
428
+ * the same layer works inside a virtualized `<epdf-stage>` page and a future
429
+ * standalone `<epdf-page-view>`.
430
+ *
431
+ * THE STABILITY INVARIANT (the one performance rule of this adapter): a page's
432
+ * context is ONE STABLE OBJECT per mounted surface — identity never changes;
433
+ * the volatile parts (`transform`, `frame`, `pageIndex`) are signals INSIDE it.
434
+ * The per-page injector providing `EPDF_PAGE` is likewise created once. Camera
435
+ * frames then flow as signal writes — `NgTemplateOutlet` never recreates the
436
+ * embedded views, in-flight renders survive, and updates stay per-binding.
437
+ * Never rebuild the context or the injector per frame.
438
+ *
439
+ * Coordinate math lives in `@embedpdf/core-geometry`'s `PageTransform` — verified
440
+ * once, not re-derived per framework adapter (`toPagePoint` mirrors React's
441
+ * `makePageContext` exactly).
442
+ */
443
+ const EPDF_PAGE = new InjectionToken('EPDF_PAGE');
444
+ function injectPage() {
445
+ const page = inject(EPDF_PAGE, { optional: true });
446
+ if (!page) {
447
+ throw new Error('[embedpdf] injectPage() must be used inside an <epdf-stage> page template');
448
+ }
449
+ return page;
450
+ }
451
+ /** Build a page context from its reactive parts. `documentId`/`pon` are thunks
452
+ * because inputs aren't readable at construction — both are stable per surface. */
453
+ function createPageContext(parts) {
454
+ const { transform, getRect } = parts;
455
+ return {
456
+ get documentId() {
457
+ return parts.documentId();
458
+ },
459
+ get pon() {
460
+ return parts.pon();
461
+ },
462
+ pageIndex: parts.pageIndex,
463
+ frame: parts.frame,
464
+ transform,
465
+ toPagePoint: (clientX, clientY) => {
466
+ // Client → box-local view px, then invert rotation + scale via the
467
+ // transform (verified once in geometry, not re-derived per adapter).
468
+ const r = getRect();
469
+ return transform().viewToPage({ x: clientX - r.left, y: clientY - r.top });
470
+ },
471
+ toClientPoint: (p) => {
472
+ // Exact inverse of `toPagePoint`, offset by the same live display-box
473
+ // origin — the two can never drift.
474
+ const r = getRect();
475
+ const v = transform().pageToView(p);
476
+ return { x: r.left + v.x, y: r.top + v.y };
477
+ },
478
+ toClientRect: (rect) => {
479
+ const r = getRect();
480
+ const v = transform().pageToViewRect(rect);
481
+ return { x: r.left + v.x, y: r.top + v.y, width: v.width, height: v.height };
482
+ },
483
+ };
484
+ }
485
+
486
+ /**
487
+ * @embedpdf/angular/runtime — the trunk: the generic kernel binding.
488
+ *
489
+ * Binds the kernel's one change stream to Angular signals (one tick signal +
490
+ * computed), resolves capabilities (document-scoped ones against the active or
491
+ * `[epdfDocumentScope]`-given document), and provides the page context seam.
492
+ * Every feature entry point and layer rides on this — there is no per-plugin
493
+ * framework code.
494
+ */
495
+ // One-line-per-feature: registration travels with the UI.
496
+
497
+ /**
498
+ * Generated bundle index. Do not edit.
499
+ */
500
+
501
+ export { EPDF_DOCUMENT_SCOPE, EPDF_PAGE, EpdfDocumentGate, EpdfDocumentScope, EpdfKernelHost, EpdfViewer, createPageContext, injectActiveDocumentId, injectCapability, injectCapabilityFor, injectDocumentId, injectDocuments, injectKernel, injectKernelHost, injectKernelValue, injectOptionalCapability, injectOptionalCapabilityFor, injectOptionalSelector, injectOptionalSelectorFor, injectPage, injectSelector, injectSelectorFor, provideEmbedPdf, shallowArray };
502
+ //# sourceMappingURL=embedpdf-angular-runtime.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedpdf-angular-runtime.mjs","sources":["../../runtime/src/kernel-host.ts","../../runtime/src/tokens.ts","../../runtime/src/inject.ts","../../runtime/src/scope.ts","../../runtime/src/viewer.ts","../../runtime/src/page-context.ts","../../runtime/src/public_api.ts","../../runtime/src/embedpdf-angular-runtime.ts"],"sourcesContent":["/**\n * The kernel host — one service owns the kernel; ONE tick signal bridges the\n * kernel's single change stream into Angular's signal graph. Everything else in\n * this adapter is `computed()` over it (`value()` is Angular's `useKernelValue`).\n *\n * Two hosting modes share this class:\n * component-hosted `<epdf-viewer [engine] [plugins]>` (framework parity)\n * provider-hosted `provideEmbedPdf({...})` at route/app level\n *\n * CONSTRUCTION RULE (library law): nothing may read `host.kernel` while a\n * component is being CONSTRUCTED. Component-hosted configs resolve their inputs\n * lazily, so the kernel materializes on first real read (a template binding, an\n * effect) — after inputs are set. Every inject* primitive returns signals or\n * lazy methods and therefore respects this for free; only the raw\n * `injectKernel()` escape hatch can violate it (its doc says so).\n *\n * SSR CONTRACT: the EmbedPDF subtree is browser-only. On the server the host\n * never boots and any `kernel` read throws — wrap the viewer region in `@defer`\n * (which renders its placeholder on the server) or a platform-guarded `@if`.\n */\nimport {\n computed,\n inject,\n Injectable,\n makeEnvironmentProviders,\n PLATFORM_ID,\n signal,\n type EnvironmentProviders,\n type OnDestroy,\n type Signal,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { createKernel } from '@embedpdf/core';\nimport type {\n AnyPlugin,\n Engine,\n EngineFactory,\n InitialDocument,\n Kernel,\n Unsubscribe,\n} from '@embedpdf/core';\n\n/** One boot document — the KERNEL's shared `InitialDocument` shape (same as\n * the React adapter's), aliased under the package's Epdf naming. */\nexport type EpdfInitialDocument = InitialDocument;\n\nexport interface EmbedPdfConfig {\n /**\n * The engine, as an instance or a thunk. Engines construct synchronously and\n * boot lazily (`localEngine()` allocates nothing until first use), so\n * ownership follows the SHAPE of what you pass:\n *\n * - An **instance** is BORROWED: used as-is, never destroyed here. The\n * common path — a module-scope `const engine = localEngine()` shared\n * across viewers and route changes. The host calls `engine.warmup?.()`\n * when the kernel materializes so the boot overlaps initialization.\n * - A **thunk** (`() => localEngine()`) is HOST-OWNED: the host calls it\n * when the kernel materializes and `destroy()`s the result on teardown.\n * Use it for per-host isolation.\n *\n * Init-only: the kernel is never rebuilt for a new engine — tear the host\n * down (destroy the viewer / injector) and create a new one.\n */\n engine: Engine | EngineFactory;\n /** Init-only, like `engine`. */\n plugins: AnyPlugin[];\n /** Documents to open on startup (with optional tab names). They open in the\n * BACKGROUND after start and stream into the registry — `injectDocuments()`\n * is reactive; per-document loading UI is the Stage's job. A source that\n * fails to open lands in `error` and does NOT block the ones after it. */\n initialDocuments?: EpdfInitialDocument[];\n}\n\n/** `starting` covers construction through `kernel.start()`; `ready` means the\n * workspace is live (documents may still be opening in the background). */\nexport type EpdfKernelStatus = 'starting' | 'ready' | 'error';\n\n@Injectable()\nexport class EpdfKernelHost implements OnDestroy {\n private readonly browser = isPlatformBrowser(inject(PLATFORM_ID));\n private config: (() => EmbedPdfConfig) | null = null;\n private _kernel: Kernel | null = null;\n /** The engine backing the kernel, and whether WE created it (a recipe) and\n * therefore must destroy it. A borrowed instance is left untouched. */\n private _engine: Engine | null = null;\n private ownsEngine = false;\n private unsubscribe: Unsubscribe | null = null;\n private initialDocuments: EpdfInitialDocument[] | undefined;\n private booted = false;\n private destroyed = false;\n\n /** Bumped on every kernel notification — THE bridge from kernel-world to signals. */\n private readonly tick = signal(0);\n\n /** Boot lifecycle. `ready`/`error` are derived sugar over it. */\n readonly status = signal<EpdfKernelStatus>('starting');\n /** The STARTUP failure, if any. Per-document open failures are tab state\n * (`DocInfo.status === 'error'`), not host state. */\n readonly error = signal<unknown>(null);\n /** True once `kernel.start()` resolved — which never touches the engine, so\n * the shell (and every workspace capability: i18n, view-manager, …) is alive\n * while WASM compiles or the transport connects. Workspace chrome may render\n * before this; gate on it (or on the document gate) where it matters. */\n readonly ready: Signal<boolean> = computed(() => this.status() === 'ready');\n\n /** Register the (deferred) config. Called exactly once, by `EpdfViewer`'s\n * constructor or `provideEmbedPdf`'s factory. */\n connect(config: () => EmbedPdfConfig): void {\n if (this.config || this._kernel) {\n throw new Error('[embedpdf] kernel already configured for this injector');\n }\n this.config = config;\n }\n\n /** The kernel — materialized on first read (see the construction rule above). */\n get kernel(): Kernel {\n if (!this._kernel) {\n if (!this.browser) {\n throw new Error(\n '[embedpdf] the viewer does not render on the server — wrap the EmbedPDF subtree in @defer (its placeholder renders during SSR) or a browser-only @if',\n );\n }\n if (!this.config) {\n throw new Error(\n '[embedpdf] no kernel: wrap this subtree in <epdf-viewer> or add provideEmbedPdf(...) to your providers',\n );\n }\n const { engine, plugins, initialDocuments } = this.config();\n // A thunk is host-owned: call it now, destroy on teardown. An instance is\n // borrowed and left untouched. Either way construction is synchronous and\n // inert (engines boot lazily on first use).\n this.ownsEngine = typeof engine === 'function';\n this._engine = this.ownsEngine ? (engine as EngineFactory)() : (engine as Engine);\n try {\n this._kernel = createKernel({ engine: this._engine, plugins });\n } catch (error) {\n // ngOnDestroy() only tears down via `_kernel`, which stays null on this\n // path — so an owned engine must be destroyed HERE or it leaks.\n if (this.ownsEngine) void this._engine.destroy();\n this._engine = null;\n this.ownsEngine = false;\n throw error;\n }\n // Warm up only once the kernel exists (a plugin-planning throw must not\n // start a boot we'd immediately have to unwind) — `warmup()` overlaps the\n // WASM/transport boot with the rest of initialization.\n this._engine.warmup?.();\n this.initialDocuments = initialDocuments;\n this.unsubscribe = this._kernel.subscribe(() => this.tick.update((n) => n + 1));\n }\n return this._kernel;\n }\n\n /** Start the kernel and open initial documents in the background. Idempotent;\n * a no-op on the server and after destroy. */\n boot(): void {\n if (this.booted || this.destroyed || !this.browser) return;\n this.booted = true;\n const kernel = this.kernel;\n void (async () => {\n try {\n await kernel.start();\n } catch (err) {\n if (!this.destroyed) {\n this.error.set(err);\n this.status.set('error');\n }\n return;\n }\n if (this.destroyed) return;\n this.status.set('ready');\n // Kernel-owned boot policy: all tabs appear immediately in array order;\n // the `active` entry (else the first) is selected; per-document\n // failures surface as that tab's `error`/`locked` status (this host's\n // `error` signal reports only startup failures).\n kernel.documents.openAll(this.initialDocuments ?? []);\n })();\n }\n\n /** Read a value derived from the kernel, cached by equality — Angular's\n * `useKernelValue`. The selector re-runs per kernel notification (cheap);\n * `equal` decides whether dependents ever see it. */\n value<R>(select: (kernel: Kernel) => R, equal: (a: R, b: R) => boolean = Object.is): Signal<R> {\n return computed(\n () => {\n this.tick();\n return select(this.kernel);\n },\n { equal },\n );\n }\n\n ngOnDestroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.unsubscribe?.();\n // destroy() owns the full teardown now: it joins an in-flight start, closes\n // every document (engine handles included), and unwinds workspace plugins.\n // Async + idempotent, so fire-and-forget is safe in a sync ngOnDestroy.\n // Then destroy the engine IF we own it (a thunk) — kernel first so handles\n // close before the engine goes; `engine.destroy()` joins any in-flight\n // boot or no-ops if it never started.\n if (this._kernel) {\n const engine = this._engine;\n const owns = this.ownsEngine;\n void this._kernel.destroy().then(() => {\n if (owns && engine) void engine.destroy();\n });\n }\n }\n}\n\n/**\n * Host the kernel in an environment injector (route or application providers).\n * The kernel's lifetime is the injector's — a route-level workspace tears down\n * when the route does. Unlocks chrome OUTSIDE any viewer subtree: a toolbar in\n * the app header and the stage in the main outlet share this one kernel.\n */\nexport function provideEmbedPdf(config: EmbedPdfConfig): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: EpdfKernelHost,\n useFactory: () => {\n const host = new EpdfKernelHost();\n host.connect(() => config);\n host.boot();\n return host;\n },\n },\n ]);\n}\n","/**\n * DI tokens shared by the runtime's primitives and directives — split out so\n * `inject.ts` (consumers) and `scope.ts` (providers) never import each other.\n */\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/** The document a subtree is bound to (provided by `[epdfDocumentScope]`).\n * Absent => the subtree follows the ACTIVE document. */\nexport interface EpdfDocumentScopeRef {\n readonly id: Signal<string>;\n}\n\nexport const EPDF_DOCUMENT_SCOPE = new InjectionToken<EpdfDocumentScopeRef>('EPDF_DOCUMENT_SCOPE');\n","/**\n * The inject* primitives — Angular's spelling of the React runtime hooks\n * (`use*` → `inject*`, plain values → signals, same names otherwise).\n *\n * All of them must run in an injection context (a constructor / field\n * initializer, like `inject()` itself). None of them read `host.kernel` during\n * construction — they return signals or lazy methods, so they are safe in\n * component-hosted mode where the kernel materializes after construction.\n */\nimport { computed, inject, type Signal } from '@angular/core';\nimport { docInfoListEquals } from '@embedpdf/core';\nimport type { CapabilityToken, DocInfo, Kernel } from '@embedpdf/core';\nimport { EpdfKernelHost } from './kernel-host';\nimport { EPDF_DOCUMENT_SCOPE } from './tokens';\n\nexport const shallowArray = <T>(a: readonly T[], b: readonly T[]): boolean =>\n a === b || (a.length === b.length && a.every((x, i) => x === b[i]));\n\nexport function injectKernelHost(): EpdfKernelHost {\n const host = inject(EpdfKernelHost, { optional: true });\n if (!host) {\n throw new Error(\n '[embedpdf] no kernel: wrap this subtree in <epdf-viewer> or add provideEmbedPdf(...) to your providers',\n );\n }\n return host;\n}\n\n/** The raw kernel — materializes it immediately. Do NOT call while a component\n * is being constructed in component-hosted mode (inputs are not set yet);\n * prefer the signal-returning primitives, which defer the first kernel read. */\nexport function injectKernel(): Kernel {\n return injectKernelHost().kernel;\n}\n\n/** Read a value derived from the kernel, cached by equality — `useKernelValue`. */\nexport function injectKernelValue<R>(\n select: (kernel: Kernel) => R,\n equal?: (a: R, b: R) => boolean,\n): Signal<R> {\n return injectKernelHost().value(select, equal);\n}\n\nexport function injectActiveDocumentId(): Signal<string | null> {\n return injectKernelValue((k) => k.documents.activeId());\n}\n\n/** The document id for this injector subtree: the nearest `[epdfDocumentScope]`,\n * else the active document. */\nexport function injectDocumentId(): Signal<string | null> {\n const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });\n const active = injectActiveDocumentId();\n return computed(() => scope?.id() ?? active());\n}\n\n/**\n * Resolve a capability against a REACTIVE token — for components that take the\n * token as an input (`injectCapability` is the fixed-token sugar). Resolution\n * is a REACTIVE read (`tryCapability` through the kernel's one change\n * stream), not a computed over the document id — under the request-time\n * lifecycle a document can become resolvable while its id stays the same, so\n * any id-keyed cache goes stale; subscribing makes staleness structurally\n * impossible. Fail-fast like React's `useCapability`: while unresolvable,\n * this re-runs the strict resolver so the kernel's truthful reason (`no\n * capability` / `no document` / `document is loading|locked`) is what throws.\n */\nexport function injectCapabilityFor<T>(token: () => CapabilityToken<T>): Signal<T> {\n const host = injectKernelHost();\n const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });\n const cap = host.value((k) => k.tryCapability(token(), scope?.id() ?? undefined));\n return computed(() => cap() ?? host.kernel.capability(token(), scope?.id() ?? undefined));\n}\n\nexport function injectCapability<T>(token: CapabilityToken<T>): Signal<T> {\n return injectCapabilityFor(() => token);\n}\n\n/** Like `injectCapabilityFor`, but null while the token can't resolve (no\n * plugin, no document, or a document that isn't ready yet). */\nexport function injectOptionalCapabilityFor<T>(token: () => CapabilityToken<T>): Signal<T | null> {\n const host = injectKernelHost();\n const scope = inject(EPDF_DOCUMENT_SCOPE, { optional: true });\n return host.value((k) => k.tryCapability(token(), scope?.id() ?? undefined));\n}\n\nexport function injectOptionalCapability<T>(token: CapabilityToken<T>): Signal<T | null> {\n return injectOptionalCapabilityFor(() => token);\n}\n\n/** Subscribe to a selector over a (document-resolved) capability. */\nexport function injectSelectorFor<C, R>(\n token: () => CapabilityToken<C>,\n select: (cap: C) => R,\n equal?: (a: R, b: R) => boolean,\n): Signal<R> {\n const host = injectKernelHost();\n const cap = injectCapabilityFor(token);\n return host.value(() => select(cap()), equal);\n}\n\nexport function injectSelector<C, R>(\n token: CapabilityToken<C>,\n select: (cap: C) => R,\n equal?: (a: R, b: R) => boolean,\n): Signal<R> {\n return injectSelectorFor(() => token, select, equal);\n}\n\n/**\n * Null-safe `injectSelector`: `fallback` whenever the token can't resolve — no\n * provider, or a document-scoped token with no document. For chrome that stays\n * mounted across the empty-workspace state (a zoom readout, a mode band).\n * `injectSelector` stays strict (fail-fast) for code that KNOWS a document\n * exists — e.g. anything behind the document gate.\n *\n * The `select` guard also swallows reads through a capability whose document\n * closed between the store notification and this read — that teardown race\n * resolves to `fallback` for one frame, then recomputes against the new state.\n */\nexport function injectOptionalSelectorFor<C, R>(\n token: () => CapabilityToken<C>,\n select: (cap: C) => R,\n fallback: R,\n equal?: (a: R, b: R) => boolean,\n): Signal<R> {\n const host = injectKernelHost();\n const cap = injectOptionalCapabilityFor(token);\n return host.value(() => {\n const c = cap();\n if (c === null) return fallback;\n try {\n return select(c);\n } catch {\n return fallback;\n }\n }, equal);\n}\n\nexport function injectOptionalSelector<C, R>(\n token: CapabilityToken<C>,\n select: (cap: C) => R,\n fallback: R,\n equal?: (a: R, b: R) => boolean,\n): Signal<R> {\n return injectOptionalSelectorFor(() => token, select, fallback, equal);\n}\n\n/** The document registry (open/close/active/list), reactive — `useDocuments`.\n * Methods late-bind the kernel, so this is construction-safe. */\nexport interface EpdfDocuments {\n docs: Signal<DocInfo[]>;\n activeId: Signal<string | null>;\n open: Kernel['documents']['open'];\n unlock: Kernel['documents']['unlock'];\n close: Kernel['documents']['close'];\n setActive: Kernel['documents']['setActive'];\n move: Kernel['documents']['move'];\n swap: Kernel['documents']['swap'];\n download: Kernel['documents']['download'];\n downloadLayer: Kernel['documents']['downloadLayer'];\n}\n\nexport function injectDocuments(): EpdfDocuments {\n const host = injectKernelHost();\n return {\n docs: host.value((k) => k.documents.list(), docInfoListEquals),\n activeId: host.value((k) => k.documents.activeId()),\n open: (input, options) => host.kernel.documents.open(input, options),\n unlock: (id, input) => host.kernel.documents.unlock(id, input),\n close: (id) => host.kernel.documents.close(id),\n setActive: (id) => host.kernel.documents.setActive(id),\n move: (id, toIndex) => host.kernel.documents.move(id, toIndex),\n swap: (a, b) => host.kernel.documents.swap(a, b),\n download: (id, opts) => host.kernel.documents.download(id, opts),\n downloadLayer: (id) => host.kernel.documents.downloadLayer(id),\n };\n}\n","/**\n * Document scoping — hierarchical DI is Angular's native React-context.\n *\n * `[epdfDocumentScope]` binds a subtree to a SPECIFIC document (panes,\n * comparison); `*epdfDocumentGate` renders a subtree only WHILE it has one.\n * The gate is a structural directive on purpose: a template genuinely defers\n * creation, which a conditional `<ng-content>` slot cannot (Angular\n * instantiates projected content eagerly). Document-scoped UI — the Stage,\n * zoom/page controls, panels — belongs behind it (or behind the app's own\n * `@if (documentId())`); workspace chrome lives outside it.\n */\nimport {\n computed,\n Directive,\n effect,\n forwardRef,\n inject,\n input,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\nimport { injectDocumentId } from './inject';\nimport { EPDF_DOCUMENT_SCOPE, type EpdfDocumentScopeRef } from './tokens';\n\n@Directive({\n selector: '[epdfDocumentScope]',\n standalone: true,\n providers: [{ provide: EPDF_DOCUMENT_SCOPE, useExisting: forwardRef(() => EpdfDocumentScope) }],\n})\nexport class EpdfDocumentScope implements EpdfDocumentScopeRef {\n readonly id = input.required<string>({ alias: 'epdfDocumentScope' });\n}\n\n/**\n * Render the host template only while this subtree has a document — the\n * structural way to say \"this UI is defined over a document\". Sibling of\n * `[epdfDocumentScope]`, which picks WHICH document; this one handles WHETHER.\n *\n * <section *epdfDocumentGate=\"; fallback: empty\">…document UI…</section>\n * <ng-template #empty>Drop a PDF to get started</ng-template>\n *\n * The subtree stays mounted across a CHANGE of document (active-tab switch) —\n * only the has-a-document boolean creates/destroys it.\n */\n@Directive({ selector: '[epdfDocumentGate]', standalone: true })\nexport class EpdfDocumentGate {\n /** Shown while this subtree has NO document (empty workspace, docs still opening). */\n readonly fallback = input<TemplateRef<unknown> | null>(null, {\n alias: 'epdfDocumentGateFallback',\n });\n\n constructor() {\n const docId = injectDocumentId();\n const hasDocument = computed(() => docId() !== null);\n const container = inject(ViewContainerRef);\n const content = inject<TemplateRef<unknown>>(TemplateRef);\n effect(() => {\n container.clear();\n if (hasDocument()) {\n container.createEmbeddedView(content);\n } else {\n // `fallback` is only tracked while gated — swapping fallback templates\n // never recreates live document UI.\n const fallbackTemplate = this.fallback();\n if (fallbackTemplate) container.createEmbeddedView(fallbackTemplate);\n }\n });\n }\n}\n","/**\n * `<epdf-viewer>` — component-hosted kernel (framework parity with React's\n * `<Viewer>`). Provides `EpdfKernelHost` at its element injector, boots it, and\n * projects content UNCONDITIONALLY: it is NOT a gate. Angular instantiates\n * projected content eagerly whether or not a slot renders it, so a conditional\n * `<ng-content>` cannot defer anything — real gating belongs to templates the\n * APP owns: `@if (ready())` for boot chrome, `*epdfDocumentGate` (or\n * `@if (documentId())`) for document UI.\n *\n * Prefer `provideEmbedPdf(...)` at route/app level when chrome lives outside\n * one subtree; this component is sugar over the same host.\n */\nimport { ChangeDetectionStrategy, Component, inject, input, type OnInit } from '@angular/core';\nimport type { AnyPlugin, Engine, EngineFactory } from '@embedpdf/core';\nimport { EpdfKernelHost, type EpdfInitialDocument } from './kernel-host';\n\n@Component({\n selector: 'epdf-viewer',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [EpdfKernelHost],\n // Layout-transparent, like React's element-less <Viewer>.\n host: { style: 'display: contents;' },\n template: `<ng-content />`,\n})\nexport class EpdfViewer implements OnInit {\n /** The engine, as an instance OR a thunk ({@link EngineFactory}). An\n * instance is borrowed (never destroyed here); a thunk is host-owned\n * (constructed then destroyed with the viewer). See EmbedPdfConfig.\n * Init-only: the kernel is built once from the first values; recreate the\n * viewer (e.g. with @if) to swap it. */\n readonly engine = input.required<Engine | EngineFactory>();\n readonly plugins = input.required<AnyPlugin[]>();\n readonly initialDocuments = input<EpdfInitialDocument[]>();\n\n /** The host this viewer provides — exposed so a template reference can read\n * `viewer.host.ready()` / `.status()` without extra imports. */\n readonly host = inject(EpdfKernelHost, { self: true });\n\n constructor() {\n // Deferred config: inputs are READ on first kernel access, which happens\n // after construction (a template binding or effect) — never here.\n this.host.connect(() => ({\n engine: this.engine(),\n plugins: this.plugins(),\n initialDocuments: this.initialDocuments(),\n }));\n }\n\n ngOnInit(): void {\n // Inputs are set by now; materializes the kernel and starts it (no-op on\n // the server — the SSR contract lives on the host).\n this.host.boot();\n }\n}\n","/**\n * PageContext — the seam. A layer depends ONLY on this, never on the Stage, so\n * the same layer works inside a virtualized `<epdf-stage>` page and a future\n * standalone `<epdf-page-view>`.\n *\n * THE STABILITY INVARIANT (the one performance rule of this adapter): a page's\n * context is ONE STABLE OBJECT per mounted surface — identity never changes;\n * the volatile parts (`transform`, `frame`, `pageIndex`) are signals INSIDE it.\n * The per-page injector providing `EPDF_PAGE` is likewise created once. Camera\n * frames then flow as signal writes — `NgTemplateOutlet` never recreates the\n * embedded views, in-flight renders survive, and updates stay per-binding.\n * Never rebuild the context or the injector per frame.\n *\n * Coordinate math lives in `@embedpdf/core-geometry`'s `PageTransform` — verified\n * once, not re-derived per framework adapter (`toPagePoint` mirrors React's\n * `makePageContext` exactly).\n */\nimport { InjectionToken, inject, type Signal } from '@angular/core';\nimport type { PageFrame, PageTransform, Point, Rect } from '@embedpdf/core-geometry';\n\nexport interface EpdfPageContext {\n readonly documentId: string;\n /** Durable page identity (PDF object number) — use for keys / render / annotations. */\n readonly pon: number;\n /** Display index (page N) — can shift under page reorders, hence a signal. */\n readonly pageIndex: Signal<number>;\n /** Reserved chrome bands around the page (screen px per side). */\n readonly frame: Signal<PageFrame>;\n /** The single bridge between PDF points, view px, and device px for this\n * page. Layers do ALL coordinate work through it — never re-derive\n * `x * scale` or `* dpr`. Updates per camera frame. */\n readonly transform: Signal<PageTransform>;\n /** Client (screen) point → PDF point — the one platform-bound hit-test. */\n toPagePoint(clientX: number, clientY: number): Point;\n /** PDF/content point → client (screen) px — the exact inverse of `toPagePoint`. */\n toClientPoint(p: Point): Point;\n /** PDF/content rect → client (screen) px AABB. */\n toClientRect(rect: Rect): Rect;\n}\n\nexport const EPDF_PAGE = new InjectionToken<EpdfPageContext>('EPDF_PAGE');\n\nexport function injectPage(): EpdfPageContext {\n const page = inject(EPDF_PAGE, { optional: true });\n if (!page) {\n throw new Error('[embedpdf] injectPage() must be used inside an <epdf-stage> page template');\n }\n return page;\n}\n\n/** Build a page context from its reactive parts. `documentId`/`pon` are thunks\n * because inputs aren't readable at construction — both are stable per surface. */\nexport function createPageContext(parts: {\n documentId: () => string;\n pon: () => number;\n pageIndex: Signal<number>;\n frame: Signal<PageFrame>;\n transform: Signal<PageTransform>;\n /** The rotated content wrapper's LIVE bounding box (the page's display box). */\n getRect: () => DOMRect;\n}): EpdfPageContext {\n const { transform, getRect } = parts;\n return {\n get documentId() {\n return parts.documentId();\n },\n get pon() {\n return parts.pon();\n },\n pageIndex: parts.pageIndex,\n frame: parts.frame,\n transform,\n toPagePoint: (clientX, clientY) => {\n // Client → box-local view px, then invert rotation + scale via the\n // transform (verified once in geometry, not re-derived per adapter).\n const r = getRect();\n return transform().viewToPage({ x: clientX - r.left, y: clientY - r.top });\n },\n toClientPoint: (p) => {\n // Exact inverse of `toPagePoint`, offset by the same live display-box\n // origin — the two can never drift.\n const r = getRect();\n const v = transform().pageToView(p);\n return { x: r.left + v.x, y: r.top + v.y };\n },\n toClientRect: (rect) => {\n const r = getRect();\n const v = transform().pageToViewRect(rect);\n return { x: r.left + v.x, y: r.top + v.y, width: v.width, height: v.height };\n },\n };\n}\n","/**\n * @embedpdf/angular/runtime — the trunk: the generic kernel binding.\n *\n * Binds the kernel's one change stream to Angular signals (one tick signal +\n * computed), resolves capabilities (document-scoped ones against the active or\n * `[epdfDocumentScope]`-given document), and provides the page context seam.\n * Every feature entry point and layer rides on this — there is no per-plugin\n * framework code.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/core';\nexport * from './kernel-host';\nexport * from './tokens';\nexport * from './inject';\nexport * from './scope';\nexport * from './viewer';\nexport * from './page-context';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}