Skip to content

feat(angular): initial Angular integration — drop-in viewer, docs, and marketing landing#624

Open
the-ult wants to merge 108 commits into
embedpdf:mainfrom
the-ult:feature/angular
Open

feat(angular): initial Angular integration — drop-in viewer, docs, and marketing landing#624
the-ult wants to merge 108 commits into
embedpdf:mainfrom
the-ult:feature/angular

Conversation

@the-ult
Copy link
Copy Markdown

@the-ult the-ult commented May 12, 2026

Why

I'm an Angular developer who recently went looking for a proper PDF viewer for a project. The leading option in the Angular ecosystem today is ngx-extended-pdf-viewer — it works, but it's a heavy wrap around PDF.js, doesn't match Angular 21 idioms (signals, zoneless, standalone, inject()), and has nothing like EmbedPDF's plugin architecture or the Snippet's batteries-included feature set.

Looking at the EmbedPDF source, the path to a proper Angular integration was clear: the existing framework adapters (@embedpdf/{react,vue,svelte}-pdf-viewer) are all thin wrappers around viewers/snippet adapted to their respective frameworks. There was no reason a similar Angular adapter couldn't exist — so I built one. Rather than keep it as a third-party package, contributing it back to the main repo seems like the right move: same maintenance surface, same release cadence, same docs site, same trust signal for Angular developers evaluating EmbedPDF.

This is the initial Angular release — a drop-in viewer covering the full Snippet feature set out of the box (annotation, redaction, signature, forms, search, AI, …), plus complete docs and a marketing landing. A follow-up release will add the headless tier (@embedpdf/core/angular, per-plugin injectXxx() helpers, layer components) once the API has been validated against real consumer usage of the drop-in viewer.

TL;DR

Surface Delivery
New package @embedpdf/angular-pdf-viewer — single standalone class, `` selector. Same shape as @embedpdf/{react,vue,svelte}-pdf-viewer.
New examples examples/angular-pdf-viewer/ (Playwright-tested demo), examples/angular-tailwind/ (live-demo source for docs)
New docs 21 MDX pages under website/src/content/docs/angular/ — same page list as /docs/{react,vue,svelte}/
New landing /angular-pdf-viewer route + landing component, fuchsia/pink/violet accent matching the current Angular brand mark
New build mode defineLibrary('angular') in @embedpdf/build (AnalogJS Vite for dev); ng-packagr produces the published APF artifact
Homepage updates AngularIcon, hero badge, Two-Ways-to-Integrate links, CodeShowcase Angular tab, Headless chip
Tailwind config Minor extension (one new color shade, one default-restoring move) — also fixes pre-existing silent class drops in sibling landings

Volume: 105 commits, 162 files changed, +13,511 / −945 LOC.

Scope

Included in this release

  • A drop-in viewer wrapping viewers/snippet, same shape as the existing React/Vue/Svelte adapters. Single [config] input, full Snippet feature set baked in.
  • provideEmbedPdfViewerConfig({...}) DI provider for cascading defaults across nested viewers (theme preference, etc.).
  • Signal-based outputs (init, ready, themechange) plus signal-typed container and registry accessors. No RxJS bridging required.
  • SSR-safe: server renders an empty placeholder, browser mounts in afterNextRender. DestroyRef.onDestroy cleanup.
  • Complete docs: introduction, getting-started, engine, customizing-ui, theme, security + 13 plugin pages. Same page list as /docs/{react,vue,svelte}/.
  • Marketing surface at parity with the existing per-framework landings.

Deferred to a follow-up release

  • Headless tier@embedpdf/core/angular, provideEmbedPdf, injectXxx(), layer components (/ / /). The follow-up release will start with the minimum-viable-render plugin set (document-manager, viewport, scroll, render, tiling, interaction-manager), with viewing essentials (zoom, pan, rotate, selection, search, …) following.
  • ng add schematicgetting-started.mdx covers the manual wiring until this lands.

Out of scope (separate issues if/when there's demand)

  • Angular Material variant of the landing page.
  • Spartan/ng deeper showcase. (The logo appears in the UI-library row on the landing; nothing beyond that.)
  • UI-library-specific examples (examples/angular-material, etc.).

The headless docs route ships as a Coming soon placeholder pointing at the follow-up release. No aspirational @embedpdf/core/angular snippet appears in marketing copy — the API is allowed to drift before it ships.


What ships — by area

1. viewers/angular/@embedpdf/angular-pdf-viewer

The Angular adapter. Same shape as @embedpdf/{react,vue,svelte}-pdf-viewer: a thin wrapper around viewers/snippet. Single standalone class PDFViewer (selector ``).

  • src/pdf-viewer.component.ts — the component
  • src/pdf-viewer.config.ts — config type + provideEmbedPdfViewerConfig DI provider
  • src/plugin-signals.tscreatePluginCapabilitySignal / createDocumentScopeSignal helpers for advanced consumers reaching into the registry
  • src/index.ts — barrel
  • Tests: pdf-viewer.component.spec.ts (TestBed unit), plugin-signals.spec.ts, smoke.browser.spec.ts (vitest browser mode under Playwright)

Naming: class PDFViewer (not PDFViewerComponent). Cross-framework symmetry with @embedpdf/{react,vue,svelte}-pdf-viewer; Angular 21's style guide is also moving away from the Component suffix.

2. examples/

  • examples/angular-pdf-viewer/ — Playwright-tested demo app. Used as the conformance/lifecycle test fixture for viewers/angular.
  • examples/angular-tailwind/ — live-demo source for the docs and the landing-page mount. Imported by useAngularMount in website/.

Both follow the existing examples/{react,vue,svelte}-pdf-viewer shape.

3. website/src/content/docs/angular/ — 21 MDX pages

Same page list as /docs/{react,vue,svelte}/. Written manually (no machine translation), Angular 21 idioms throughout (signals, @if/@for, standalone, inject(), no NgModule, no *ngIf).

Top-level (8):

  • index.mdx, viewer/introduction.mdx, viewer/getting-started.mdx, viewer/engine.mdx, viewer/customizing-ui.mdx, viewer/theme.mdx, viewer/security.mdx, headless/introduction.mdx (placeholder for the follow-up release)

Plugin pages (13):

  • viewer/plugins/plugin-{annotation,document-manager,export,form,i18n,pan,print,rotate,scroll,selection,signature,spread,zoom}.mdx

A dedicated docs-lint test (website/src/__tests__/angular-helper-docs.test.ts) sweeps every TS/TSX code block under content/docs/angular/viewer/ and asserts that createPluginCapabilitySignal / createDocumentScopeSignal helpers are invoked (name()) before member access — catches the common copy-paste error of writing docZoom?.zoomIn() instead of docZoom()?.zoomIn() in published examples.

4. website/ — marketing surface

  • Landing page at /angular-pdf-viewer (app/angular-pdf-viewer/page.tsx + components/angular-pdf-viewer.tsx). Hero, integration paths, CodeShowcase Angular tab, live demo bootstrapping the real Angular adapter (not a React preview of it), UI library row (Angular Material + PrimeNG + Spartan/ng + Tailwind), Headless follow-up callout, plugin showcase, FAQ, CTA. Pink/fuchsia/violet accent matching the Angular brand mark.
  • Lazy-mount of the Angular demo: the ~MB of @angular/core + @angular/platform-browser + @angular/compiler JIT chunks only download once the demo section enters the viewport (IntersectionObserver, 200px rootMargin). Above-the-fold paint pays no Angular cost.
  • Homepage updates (components/homepage.tsx, components/framework-icons.tsx, components/code-showcase.tsx): new AngularIcon (current brand gradient, not the legacy red shield), Angular badge in hero "Works seamlessly with" row, Angular link in both Two-Ways-to-Integrate cards, Angular tab in CodeShowcase (filename app.component.ts, brand colors), 4th chip in HeadlessSection, 'angular' cases in SnippetSection.getDocumentationLink / getButtonText.
  • Three new logos: AngularMaterialLogo, PrimeNGLogo, SpartanNgLogo in components/logos/index.tsx.
  • Exhaustiveness guard on homepage-framework-links.ts: a compile-time check ensures the framework-links map stays in sync when new framework modes are added to FRAMEWORK_PREFIXES.

5. packages/build/defineLibrary('angular')

New Angular build mode for @embedpdf/build's defineLibrary() factory. AnalogJS Vite plugin (@analogjs/vite-plugin-angular) is used for local development and type-checking. For publishing, ng-packagr produces an APF-compliant artifact (fesm2022/, partial-Ivy .mjs, proper index.d.ts). Adds 'angular' to FRAMEWORK_PREFIXES in validate-package-exports.ts so the per-package exports-map check covers it.

Only viewers/angular/ exercises this mode in this release. Per-plugin Angular adapters in the follow-up release will plug into the same dual-path setup without further build-system changes.


How — locked decisions

Each decision below was previously documented in a fork-internal ADR. Folding the rationale into the PR description rather than introducing a docs/adr/ tree to upstream — the trade-offs survive review better as bullets.

Decision 1 — Publish via ng-packagr (APF), develop via AnalogJS Vite

The published artifact is produced by ng-packagr, which outputs a standard Angular Package Format bundle: fesm2022/embedpdf-angular-pdf-viewer.mjs, partial-Ivy compilation, and a proper index.d.ts. This is what Angular toolchains (Webpack, esbuild, Rollup) expect and link against correctly.

  • APF partial compilation is the right output contract. ng-packagr's partial-Ivy .mjs is linked by each consumer's build and is compatible across Angular minor versions without requiring consumers to know the compilation strategy.
  • AnalogJS Vite is retained for dev. vite.config.ts drives local development, TestBed tests, and the smoke suite. It provides fast type-check feedback before packaging and keeps the per-plugin build symmetry intact (defineLibrary('angular') mode).
  • CI smoke test verifies the published tarball. A pack → install → build step in the test matrix exercises the actual .tgz artifact rather than only workspace-linking, catching exports-map or peer-dep mismatches before release.
  • Trade-off: adds ng-packagr as a devDependency in viewers/angular. Per-plugin Angular subpaths in the follow-up release will follow the same dual-path setup; the additional dependency is per-viewer, not global.
  • Angular version lock (>=21.0.0) still applies. Partial compilation is compatible with any Angular version ≥14; the >=21 constraint is driven by the other decisions below (signals API, afterNextRender stability, zoneless), not by the build pipeline.

Alternatives considered: AnalogJS Vite for both dev and publish (outputs AOT-compiled FESM2022, not partial-Ivy APF — incompatible with Angular's linker expectations on consuming builds); separate Angular workspace (fragments the package graph permanently); CUSTOM_ELEMENTS_SCHEMA + Web Component (no TypeScript safety on config, no Signals integration).

Decision 2 — Component API surface

  • Selector: . Name space cleanly separated from `viewers/snippet`'s .
  • Class name: PDFViewer (not PDFViewerComponent). Cross-framework symmetry; Angular 21 style guide is moving away from the suffix.
  • Inputs: single [config] input typed as PDFViewerConfig — same flat shape consumers see in the existing per-framework docs. Cross-framework docs translate one-to-one.
  • Outputs: signal-based — init, ready, themechange outputs + container: Signal + registry: Signal accessors. No RxJS bridging required for effect() / computed() consumers.
  • Change detection: OnPush. Zoneless-compatible.
  • Defaults DI: provideEmbedPdfViewerConfig({...}) lets app or route scope cascade defaults (theme preference, etc.) into every nested `` without prop-drilling. Idiomatic Angular pattern (provideRouter, `provideHttpClient`, `provideStore`).

Decision 3 — Bootstrap via afterNextRender, not eager factory

Defers all browser-API touches (engine creation, WASM fetch, PluginRegistry instantiation, store subscription wiring) to afterNextRender. The component returns immediately with placeholder signals; the actual bootstrap fires on the client only.

  • SSR-clean by construction. Zero isPlatformBrowser(...) guards. The server platform sees null signals, the template renders its @if (registry()) { … } @else { } branch, no browser-only API is reached. Works under Angular Universal without hydration mismatches.
  • Matches the cross-framework precedent. Svelte bootstraps inside $effect; Vue inside onMounted; afterNextRender is the closest Angular analog. Same lifecycle ordering across frameworks.
  • Cooperates with zoneless change detection. First-class hook; signal updates inside the callback trigger normal CD.
  • Cleanup: DestroyRef.onDestroy(() => registry()?.destroy()). Route changes don't leak workers or WASM memory.
  • Trade-off: one frame of registry() === null on the client. Consumers must render a loading state — but they'd need it for pluginsReady anyway.

Alternatives considered: eager bootstrap gated by isPlatformBrowser (race conditions between bootstrap and first injectRegistry() read); lazy on first read (order-dependent side effects, debugging nightmare); module-level singleton (Svelte-style — can't host two viewers in one app, fights Angular DI).

Decision 4 — Headless registry shape (preview, lands in follow-up release)

When the headless tier lands in the follow-up release, the PluginRegistry context will be exposed via two parallel surfaces:

// Primary — provider function (idiomatic Angular)
bootstrapApplication(App, { providers: [provideEmbedPdf({ engine, plugins })] });

// Secondary — component for inline / per-instance scoping
  

Both resolve the same PLUGIN_REGISTRY InjectionToken. Deliberately diverges from the other framework adapters (which expose only a Provider component) because Angular has a route-scoped DI primitive that React/Vue/Svelte don't.

Not in this PR — flagging it here so reviewers can object to the shape before the follow-up PR lands. Happy to iterate.

Decision 5 — Angular version baseline: >=21.0.0

Locked peer range. Justified by:

  • afterNextRender (Angular 16+, hardened in 17+) is core to the bootstrap strategy.
  • Standalone components and inject() are the only supported authoring model — NgModule and constructor injection are not used anywhere in the new code.
  • Zoneless support is first-class in Angular 21+; this PR's signal-only API surface assumes zoneless.

Angular consumers on <21 are explicitly unsupported. Migration path: upgrade Angular, then install @embedpdf/angular-pdf-viewer. The viewers/snippet Web Component fallback (`` + CUSTOM_ELEMENTS_SCHEMA) remains available on any Angular version for shops that can't upgrade.

Decision 6 — Tailwind config touch-up (cross-cutting, minimal)

Two changes in website/tailwind.config.ts:

  • theme.extend.colors.gray.950: '#030712' — adds a dark shade used by the follow-up-release callout's fake-terminal background.
  • theme.letterSpacing moved from theme root to theme.extend (keeps custom tight: -0.015em and wider: 0.05em as overrides; restores Tailwind's defaults for tighter/normal/wide/widest).

The letterSpacing move is technically out of strict scope but fixes pre-existing silent class drops across the site: tracking-wide was used in 24 files (sibling React/Vue/Svelte landings + docs code-examples) and was silently dropping at build time because the root-level letterSpacing override only defined tight. Moving under extend is a one-line fix; doing the audit separately would mean opening a parallel docs-only PR.

theme.fontSize is left untouched at theme root — the truncated 10-step scale appears deliberate (caps marketing typography at 6xl). Flagged here in case you want to expand it later.


Testing

Layer Tooling Location
Unit Vitest (node) viewers/angular/src/plugin-signals.spec.ts
Component (TestBed) Vitest browser mode viewers/angular/src/pdf-viewer.component.spec.ts
Smoke (real browser) Vitest browser mode under Playwright viewers/angular/src/smoke.browser.spec.ts
CI smoke (pack/install/build) pnpm pack → install → ng build .github/workflows/test.yml (Angular quality checks job)
Integration Playwright examples/angular-pdf-viewer/
Docs lint Node test runner website/src/__tests__/angular-helper-docs.test.ts
Marketing next build + Playwright examples/angular-tailwind/ mounted at /angular-pdf-viewer

Conformance fixes from the PR #34 cycle ensure lifecycle ordering (init before consumer effects, ready after pluginsReady, themechange from the actual Snippet event, no leaks on DestroyRef).

CI matrix exercises Node 20 + Node 22. pnpm --filter @embedpdf/angular-pdf-viewer test runs end-to-end. The CI smoke job verifies the published .tgz tarball rather than only workspace-linking.

Consumer impact

  • Net new for Angular consumers. New optional peer dependency (@embedpdf/angular-pdf-viewer).
  • Zero breaking changes for React, Vue, Svelte, or Web Component consumers. No public API on existing packages was modified.
  • Bundle size impact on the website is gated behind IntersectionObserver — only fires when a user scrolls to the live demo on /angular-pdf-viewer.

Follow-ups (separate PRs, deliberately scoped out here)

  • Headless tier. @embedpdf/core/angular + provideEmbedPdf + injectXxx() helpers + minimum-viable-render layer components (, , , ). Six plugins to start: document-manager, viewport, scroll, render, tiling, interaction-manager. End-to-end examples/angular-custom demo.
  • Viewing-essentials plugin adapters. Eleven adapters once headless lands: zoom, pan, rotate, selection, search, spread, thumbnail, fullscreen, i18n, print, export.
  • ng add schematic. Optional follow-up; until then, getting-started.mdx walks consumers through the manual wiring.

Notes for reviewers

  • Most of the diff is new files under viewers/angular/, examples/angular-*/, and website/src/content/docs/angular/. Existing files touched are limited to: packages/build/src/vite/index.ts (new 'angular' mode), packages/build/src/vite/validate-package-exports.ts (one constant + sync guard), website/src/components/homepage.tsx + framework-icons.tsx + code-showcase.tsx (Angular tab + chips + badge), website/src/components/logos/index.tsx (three new logos), website/tailwind.config.ts (two-line extension), .github/workflows/test.yml (Angular quality checks + build ordering).
  • The Angular adapter does not import from @embedpdf/core directly — it wraps viewers/snippet, same as the existing framework adapters. No headless coupling. This release is shippable without the headless tier landing.
  • The new package's peerDependencies list @angular/core, @angular/common, @angular/platform-browser at >=21.0.0. No rxjs runtime usage — all reactivity is signals.
  • If you'd prefer an RFC Discussion before the merge review starts, happy to open one — the Why and How sections above are the content.

File-level summary (collapsed)

NEW
  viewers/angular/                                — 17 files, ~1,800 LOC (incl tests)
  examples/angular-pdf-viewer/                    — Playwright demo app
  examples/angular-tailwind/                      — 5–7 demo source files (used by docs + landing)
  website/src/content/docs/angular/               — 21 MDX pages (~6,000 LOC including code blocks)
  website/src/content/docs/angular/code-examples/ — use-angular-mount.tsx + per-demo wrappers
  website/src/app/angular-pdf-viewer/page.tsx     — landing route
  website/src/components/angular-pdf-viewer.tsx   — landing component (~860 LOC)
  website/src/__tests__/angular-helper-docs.test.ts — docs-lint test
  website/src/components/logos/index.tsx          — +3 logo exports (AngularMaterial, PrimeNG, Spartan/ng)

MODIFIED
  packages/build/src/vite/index.ts                — new 'angular' mode
  packages/build/src/vite/validate-package-exports.ts — +'angular' in FRAMEWORK_PREFIXES + sync guard
  website/src/components/homepage.tsx             — hero badge + paths links + chip
  website/src/components/homepage-framework-links.ts — exhaustiveness guard + test
  website/src/components/framework-icons.tsx      — +AngularIcon
  website/src/components/code-showcase.tsx        — +'angular' framework + tab
  website/tailwind.config.ts                      — gray.950 + letterSpacing under extend
  website/src/app/angular-pdf-viewer/page.tsx     — was a redirect stub, now renders the landing
  .github/workflows/test.yml                      — Angular quality checks, CI ordering, smoke test

Stats: 105 commits, 162 files, +13,511 / −945 LOC.

___BEGIN___COMMAND_DONE_MARKER___0

Arjen and others added 30 commits May 8, 2026 15:16
Establishes the planning artefacts for the Angular tier — a headless layer
across @embedpdf/{core,engines} + 13 plugins, a battery-included Wrapper
viewer, an ng add schematic, and a custom-toolbar example. v1.0 is sequenced
headless-first (foundation → minimum-viable-render → useful-features →
custom-example → Wrapper → schematic → docs); Material/Tailwind examples
and the remaining ~17 plugin /angular subpaths defer to v1.x.

- CONTEXT.md: domain glossary plus full Angular plan
- ADR 0001: publish via @analogjs/vite-plugin-angular, not ng-packagr
- ADR 0002: registry context via provideEmbedPdf() + <embedpdf-provider>
- docs/prd/angular-integration.md: full PRD with phase ordering
Agent-Logs-Url: https://github.com/the-ult/embed-pdf-viewer/sessions/de5eed39-63ab-427d-b96b-8705a7e3861c

Co-authored-by: the-ult <4863062+the-ult@users.noreply.github.com>
- build: spread Analog plugin array for shape-consistency with vue/svelte
- build: align angular mode with Analog library guidance
  (minify: false, target esnext, mainFields module, preserveModules false)
- build: extend ConfigOptions with optional minify/target/mainFields/
  preserveModules so non-angular modes are unaffected
- viewers/angular: rename scratch-label.component.ts -> smoke.component.ts
  with a comment explaining its role as a build-pipeline fixture; drop
  redundant standalone: true (default in Angular 21)
- viewers/angular: tighten Angular tsconfig per Analog recommendations
  (strictInjectionParameters, strictInputAccessModifiers, noImplicit
  Override, noPropertyAccessFromIndexSignature, noImplicitReturns,
  noFallthroughCasesInSwitch)
- viewers/angular: hygiene on package.json — add files/keywords/
  publishConfig, declare rimraf devDep, normalize build script to
  match react/vue convention, switch Angular pins to caret ranges
…elibrary

Add Angular mode to `@embedpdf/build` `defineLibrary()` and wire an Angular viewer smoke package
Replaces the smoke fixture from PR #25 with a working PDFViewer
standalone component, mirroring the shape established by viewers/{vue,
react,svelte}: a thin Angular wrapper that initializes @embedpdf/snippet
in a host div and emits init/ready events.

- src/pdf-viewer.component.ts: signal-based inputs (config) and outputs
  (init, ready); viewChild.required for the container ref;
  ChangeDetectionStrategy.OnPush; uses replaceChildren() for teardown
- src/index.ts: re-exports snippet plus the component
- vite.config.ts: hand-rolled per Analog's library guidance (mainFields:
  ['module'], target: esnext, minify: false, preserveModules: false);
  drops dependency on @embedpdf/build's defineLibrary() so the Angular
  viewer aligns with the single-entry shape of the existing viewers
- tsconfig.json: keeps Analog-recommended Angular strictness flags;
  drops noEmit (Angular compiler honors it and would skip transforms)
- package.json: collapses to single "." entry matching vue/react/svelte;
  adds @embedpdf/snippet as a runtime dep; drops @embedpdf/build dep
  since this package no longer uses defineLibrary()
- removes the smoke fixture, src/shared, and the src/angular subtree
Brings @embedpdf/angular-pdf-viewer to a publish-ready shape:

- Vitest setup via @analogjs/vitest-angular with zoneless TestBed
  (per https://analogjs.org/docs/features/testing/vitest)
- 4 smoke tests covering: host renders a container div, EmbedPDF.init
  is called with the host div as target, init/ready outputs emit when
  the snippet returns a viewer, container is cleared on destroy
- README mirroring the structure of viewers/{vue,react,svelte}/README
  with Angular 21 idioms (signal-based config input, OnPush template,
  standalone usage)
- Changeset for initial 0.1.0 release

The vite.config.ts gains a test block (jsdom + setupFiles) and the
dts pass excludes spec/test-setup files from declaration emission.
… add A0 pre-flight

PRD revision after grilling pass:
- v1.0 plugin scope grew from 13 to 17 (added fullscreen, i18n, print, export
  for "read-only viewing only" parity with the Svelte tracer)
- Phase E (Wrapper) documented as parallel-shippable with B-D (only depends on
  A0 + A1 + Snippet, not per-plugin /angular adapters)
- Phase F schematic split into drop-in (default) and --headless flows
- Wrapper class renamed PdfViewer -> PDFViewer for cross-framework symmetry
  (single explicit exception to the Angular ALLCAPS-in-identifiers rule)
- Module 8 added: Vitest pipeline (Node + browser mode via @analogjs/vitest-angular).
  Drops Playwright entirely from v1.0
- A0 added as pre-flight: fix #27 (silent dts gap on pure re-export entries)
  + wire vitest workspace + revive dormant packages/models/*.test.ts + CI gating
- bridgeScopeState + bridgeCoreSignal locked into Module 2's deliverables to
  keep per-plugin adapters mechanical
- Standard issue preamble inlined: each plugin issue requires a review pass over
  the Svelte/Vue/React adapters before implementation, mapping primitives to
  Angular 21 best practices
- Story 54 (cross-framework code-tabs) dropped; out of scope for this PRD
- Phase G adds a migration page from ngx-extended-pdf-viewer
- v1.x roadmap made concrete: v1.1 editing surface, v1.2 forms+navigation+history,
  v2.0 AI/specialised
- CI gating split: Node-mode tests on every PR; browser-mode tests path-filtered
  to Angular-touching PRs
feat(angular): real PDFViewer component (replaces #25 smoke fixture)
…t pipeline

Closes #28. Unblocks Phase A2/A3/B/C/E/F/G of the Angular integration.

defineLibrary() now emits dist/index.d.ts for pure `export *` re-export
entries (insertTypesEntry: true) and ships a build-time validator that
fails if any package.json-advertised types/exports target is missing.

First real test runner in the repo: vitest 4 with per-package configs
glued by a root vitest.config.ts using the modern `test.projects` key,
orchestrated by a new turbo `test` task with dependsOn ["build", "^build"].

Revived the dormant packages/models/src/*.test.ts suite (jest.fn → vi.fn,
removed @types/jest + jest deps). Added a chromium browser-mode smoke
test in viewers/angular via @analogjs/vitest-angular +
@vitest/browser-playwright, gated in CI by dorny/paths-filter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add hookTimeout: 60_000 to packages/build/vitest.config.ts so the
  fixture-build subprocess in beforeAll() doesn't trip Vitest's 10s
  hook default on slower CI machines.
- Fix root test:browser script — was running turbo's `test` task
  (jsdom config) instead of the package's `test:browser` script.
  Now invokes the chromium config directly via pnpm filter.
- Add vite ^6.3.5 to @embedpdf/models devDependencies so Vitest
  resolves against the repo's pinned Vite 6 instead of pulling in
  a parallel Vite 7 from its peer range.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the PDF viewer's class lifecycle hooks with afterNextRender and DestroyRef so initialization and teardown follow Angular 21's modern patterns.

Guard late registry resolution after destroy, avoid calling a required view query during teardown, and add regression coverage for destroy timing edge cases.

Ignore root .env files so the local NPM_TOKEN placeholder stays out of version control.

Co-Authored-By: GitHub Copilot <noreply@github.com>
Two adjustments after re-reading turborepo.dev/docs/guides/tools/vitest:

1. test task dependsOn — switch from ["build", "^build"] to ["^test"]
   (Turbo's documented default). Tests should run on source via Vite's
   transform pipeline, not against potentially stale dist/ artifacts.
   Single per-package override "@embedpdf/build#test" keeps ["build",
   "^test"] because its dts-emission regression test shells out a Vite
   build of a fixture and genuinely needs its own dist/.

2. Extract @embedpdf/vitest-config — a private workspace package that
   exposes three config helpers (node, angular-jsdom, angular-browser)
   directly as TS source via the exports map (no compile step, the
   modern Turbo internal-package pattern). Existing per-package
   vitest.config.ts files now extend from these. Phase B/C plugin
   packages will plug in via the same helpers without duplicating the
   AnalogJS/Playwright wiring.

Other cleanup:
- Move viewers/angular's test config out of vite.config.ts into a
  separate vitest.config.ts so the build config stays focused.
- Add test:watch task to turbo.json (cache:false, persistent:true) per
  Turbo guide.
- Add coverage/** to test outputs reserved for future coverage support.
- Drop redundant test:node root script — pnpm test now runs Node +
  jsdom suites; pnpm test:browser handles chromium separately.
- CI workflow simplified: pnpm test (Node + jsdom) on every PR;
  pnpm test:browser path-filtered.

All four suites still green: build 8/8, models 32/32, angular jsdom
4/4, angular browser 1/1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous commit followed Turborepo's Vitest guide recommendation
of `dependsOn: ["^test"]`. That guide assumes the @repo/math
"internal-package" pattern where each workspace package exports its
TypeScript source directly via the `exports` map (e.g.
`"./add": "./src/add.ts"`), so Vitest can resolve cross-package
imports without any build step.

Our workspace publishes packages to npm. Their package.json `main` /
`module` / `types` point at `./dist/...`, so any test that imports a
workspace dependency must wait for that dependency's build. CI proved
this: viewers/angular's spec imports @embedpdf/snippet, and with
`^test` snippet's dist/ was never produced, yielding:

    Error: Failed to resolve entry for package "@embedpdf/snippet"

Reverting to `^build` for the general test task and `["build",
"^build"]` for the @embedpdf/build#test override (which additionally
needs its own dist for the dts-emission regression fixture). Verified
by wiping every dist/ and the .turbo cache, then running pnpm test
from clean — 54/54 turbo tasks green.

The rest of the previous commit (shared @embedpdf/vitest-config
package, separate vitest.config.ts files, test:watch task, coverage
outputs) stands as-is.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A0 — Fix #27 dts emission + wire Vitest pipeline (closes #28)
Remove the internal wrapper div and initialize the snippet against the component host element to stay closer to the underlying web component model.

Update viewer tests to assert host-based mounting, cleanup behavior, and config forwarding for the initialized container.

Co-Authored-By: GitHub Copilot <copilot@github.com>
Create a new Angular 21.2 standalone demo app under examples/angular-pdf-viewer for manual verification of the drop-in viewer.

Bootstrap with provideZonelessChangeDetection and a minimal host layout that renders embedpdf-pdf-viewer with ready-state feedback.

Co-Authored-By: GitHub Copilot <copilot@github.com>
Add a focused Playwright smoke test for the angular-pdf-viewer demo and wire it to run through Turborepo.

Configure turbo e2e task graph, PLAYWRIGHT_* passthrough, report outputs, and root scripts for full and package-scoped e2e execution.

Exclude generated .vercel outputs from workspace discovery to avoid duplicate-workspace failures during turbo runs.

Co-Authored-By: GitHub Copilot <copilot@github.com>
…ry controls

Enhance the Angular PDF viewer example with a comprehensive config panel that
demonstrates runtime customization capabilities:

- Add collapsible config panel with animated overlay layout
- Support light/dark theme switching with Angular-branded accent colors
- Control plugin categories at runtime (annotations, search, zoom, sidebar)
- Register custom Config toolbar button via commands/ui plugin APIs
- Fix viewport sizing so viewer and config panel are always visible
- Add Playwright e2e test with screenshot baselines covering all interactions

Co-Authored-By: GitHub Copilot <copilot@github.com>
Provide an Angular DI token and provider function for shared viewer defaults and merge them with per-instance viewer config. Wire the Angular example to use app-level defaults while keeping local overrides, and document the precedence and merge rules for consumers.

Add root dev shortcuts for the framework examples so each demo can be started directly from the monorepo root.

Co-Authored-By: GitHub Copilot <noreply@github.com>
Captures the locked decisions from the 2026-05-09 design grilling for
@embedpdf/core/angular (#3) and @embedpdf/engines/angular (#4):

- ADR 0003 documents the afterNextRender bootstrap decision with the
  rejected eager (PLATFORM_ID) and lazy (first-read) alternatives. Hits
  all three ADR criteria: hard to reverse, surprising vs Svelte/Vue
  module-level state, real trade-off vs eager fetch.
- PRD Module 2 replaced with the locked API contract: provideEmbedPdf
  takes EngineConfig, <embedpdf-provider> takes a PdfEngine instance,
  bridgeScopeState uses effect+onCleanup with untracked() writes,
  bridgeCoreSignal is pure computed, two-registry detection rule with
  EmbedpdfDuplicate{Registry,Engine}Error, four-flavor engine-ownership
  table, and the defer-then-ship-as-structural-directive plan for
  auto-mount.
- CONTEXT.md adds the bridge primitives and bootstrap-timing language
  to the glossary.

Auto-mount surface deferred from v1.0 (zero v1.0 plugins emit
autoMountElements) and tracked separately as #38 — to be activated when
the first consumer plugin needs it (likely v1.1 plugin-ui or editing
surface).

A2 (#3) and A3 (#4) ship as a single PR per the design discussion;
the engine config inline ergonomic and the registry-context provider
are foundationally coupled.
Ignore Playwright reports, local env files, and common framework build outputs at the repo root.

This keeps status noise down across examples and apps without relying on per-project ignore files.

Co-Authored-By: GitHub Copilot <noreply@github.com>
Add an Angular viewer demo component with config-driven theming and runtime toolbar customization.

Document the example usage and cover the customized viewer behavior with a Playwright end-to-end test.

Co-Authored-By: GitHub Copilot <noreply@github.com>
…x/angular-viewer-lifecycle-cleanup

# Conflicts:
#	examples/angular-pdf-viewer/README.md
#	examples/angular-pdf-viewer/e2e/viewer.spec.ts
#	examples/angular-pdf-viewer/src/app/app.component.ts
#	pnpm-lock.yaml
Drop accidental copy-paste duplicates in three README sections (App-wide
defaults bullet, theming intro paragraph, Disabling Features intro
sentence) flagged by PR review.

Refs GH-34
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Promise.withResolvers() lands in Node 22+. Tests already run on Node 22
in CI, but contributors on Node 20 LTS would hit a runtime error. Swap
for the standard manual-resolve pattern so the spec runs on any
currently supported Node version.

Refs GH-34
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@angular/compiler is imported at runtime in src/main.ts to enable JIT,
so it belongs in dependencies only. Listing it under both dependencies
and devDependencies risked confusing version resolution.

Refs GH-34
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop redundant standalone: true (default since v19) and rename
AppComponent to App per the no-suffix style guide. Aligns the demo with
the conventions enforced across the @embedpdf/*/angular packages.

Refs GH-34
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Ult and others added 8 commits May 12, 2026 20:51
…ewer

EmbedPDF doesn't ship its own integrations on v1.x semver — those numbers
were fork-internal milestone names for the Angular work and bake the
maintainer's release cadence into customer-facing copy. Replace with
release-agnostic language:

  "Available today (v1.0)"        → "Available today"
  "Coming in v1.1"                → "Coming soon"
  "Headless ... arrive in v1.1."  → "Headless ... are coming soon."
  "v1.0 ships drop-in, v1.1 ..."  → "Drop-in today, headless next"
  "v1.1 of the EmbedPDF Angular …" → "The next release of the …"
  "v1.1-preview.ts" (fake tab)    → "headless-preview.ts"
  "Preview v1.1 Plan" (CTA)       → "Preview the headless plan"
  + FAQ answers + internal comments

No structural changes — pure copy + filename label. Also updates the
page.tsx meta description to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…uppression

Pre-publish polish from the v1.0 readiness review:

- Correct `themeChange` casing in the changeset body (changeset said
  `themechange` but the actual output is `themeChange`)
- Add reference-equality guard before `viewer.config = config` to skip
  redundant writes that would otherwise re-trigger the snippet's
  `renderViewer()` path
- Skip `__proto__` / `constructor` / `prototype` keys in `mergeRecord`
  as a defensive guard for configs parsed from untrusted JSON
- Suppress Rollup's `UNUSED_EXTERNAL_IMPORT` warning from `@angular/*`
  (Analog's AOT transform rewrites the decorator references)
- Add `index.test-d.ts` pinning the public API surface (input/output
  signal types, provider return types, capability-helper signatures)
- Add focused unit spec for `mergeViewerConfigs` covering deep merge,
  undefined-as-inherit semantics, and prototype-pollution refusal
Fork-internal working draft for the upcoming upstream PR (issue #24).
Sibling to docs/prd/angular-integration.md and docs/adr/*. Will be
scrubbed from the upstream diff along with the PRD and ADRs — the
rationale lives entirely in the PR body once submitted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Internal identifier was still encoding the removed v1.1 milestone.
Also normalizes two JSX section comments to lowercase coming-soon
to match the third comment that already used that casing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
"API may drift before ship" → "before it ships". Internal JSX
comment, no behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rge spec

Address Copilot review feedback on PR #49: the original assertions
(`hasOwnProperty('__proto__')`, `({}).polluted`) would silently pass even
if the merge writes `merged['__proto__']`, because the resulting prototype
replacement isn't an own-property and doesn't touch global Object.prototype.

- Assert `Object.getPrototypeOf(merged) === Object.prototype` to catch
  local prototype replacement
- Assert `merged.polluted === undefined` to catch chain pollution
- Cover the classic `constructor.prototype` nested attack pattern
- Sanity-checked by temporarily removing the guard: both tests fail
chore(website): Drop hardcoded v1.0/v1.1 strings from /angular-pdf-viewer
fix(angular): Apply v1.0 polish — guards, type tests, build warning suppression
@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

@the-ult is attempting to deploy a commit to the OpenBook Team on Vercel.

A member of the Team first needs to authorize it.

@the-ult the-ult changed the title eat(angular): initial Angular integration — drop-in viewer, docs, and marketing landing feat(angular): initial Angular integration — drop-in viewer, docs, and marketing landing May 12, 2026
Removes CONTEXT.md and docs/ (PRD, ADRs, upstream PR draft) from
feature/angular. These are fork-internal planning artifacts and don't
belong in the upstream diff — their rationale will be folded into the
upstream PR body and the heads-up Discussion (#19).

Preserved on feature/angular-v1.1, which was fast-forwarded to the
current feature/angular HEAD prior to this strip so the architectural
record remains intact for v1.1+ implementation work (issues #3, #4,
#5#18, #20, #22, #29#32, #38, #39).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@the-ult
Copy link
Copy Markdown
Author

the-ult commented May 13, 2026

@bobsingor , what do you think about this PR?

I deliberately created it as 1 big ready to merge PR, including the website, example apps, etc. So you can make sure everything is working correctly and give proper feedback on things missing or needing improvements.

When/If it is approved and merged, I will start with the headless implementations

@the-ult the-ult marked this pull request as ready for review May 14, 2026 09:42
Copilot AI review requested due to automatic review settings May 14, 2026 09:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces first-party Angular support by adding a new @embedpdf/angular-pdf-viewer package (a thin Angular 21+ wrapper around viewers/snippet), plus Angular example workspaces, Angular docs, and a new /angular-pdf-viewer marketing route on the website. It also expands the monorepo’s build/test infrastructure (Vitest projects, Turbo tasks, GitHub Actions) to cover the new Angular surface area and the new defineLibrary('angular') mode in @embedpdf/build.

Changes:

  • Add @embedpdf/angular-pdf-viewer (standalone PDFViewer component, config providers, signal helpers, unit + browser smoke tests).
  • Add Angular examples (examples/angular-pdf-viewer, examples/angular-tailwind) and mount Angular demos inside the Next.js docs site.
  • Add Angular docs + marketing landing, and extend build/test plumbing (Vitest workspace config, Turbo tasks, CI workflow updates).

Reviewed changes

Copilot reviewed 148 out of 153 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
website/tailwind.config.ts Restores Tailwind letterSpacing defaults via extend and adds gray.950.
website/src/content/docs/snippet/plugins/plugin-zoom.mdx Pins EmbedPDF version marker in Snippet docs page.
website/src/content/docs/snippet/plugins/plugin-spread.mdx Pins EmbedPDF version marker in Snippet docs page.
website/src/content/docs/snippet/getting-started.mdx Updates Snippet getting-started version marker and adds Angular to framework list.
website/src/content/docs/angular/viewer/security.mdx Adds Angular viewer security/permissions documentation.
website/src/content/docs/angular/viewer/plugins/plugin-zoom.mdx Adds Angular zoom plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-spread.mdx Adds Angular spread plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-selection.mdx Adds Angular selection plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-scroll.mdx Adds Angular scroll plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-rotate.mdx Adds Angular rotate plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-print.mdx Adds Angular print plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-pan.mdx Adds Angular pan plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-i18n.mdx Adds Angular i18n plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-form.mdx Adds Angular forms plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/plugin-export.mdx Adds Angular export plugin documentation and demo embed.
website/src/content/docs/angular/viewer/plugins/_meta.ts Adds Angular viewer plugin sidebar metadata.
website/src/content/docs/angular/viewer/introduction.mdx Adds Angular viewer introduction page.
website/src/content/docs/angular/viewer/engine.mdx Adds Angular “accessing the engine” page.
website/src/content/docs/angular/viewer/_meta.ts Adds Angular viewer section navigation metadata.
website/src/content/docs/angular/index.mdx Adds Angular docs overview/landing page.
website/src/content/docs/angular/headless/introduction.mdx Adds Angular “headless/custom integrations” placeholder page.
website/src/content/docs/angular/headless/_meta.ts Adds Angular headless section navigation metadata.
website/src/content/docs/angular/code-examples/viewer/zoom-example.tsx React wrapper that lazy-mounts Angular zoom demo inside docs.
website/src/content/docs/angular/code-examples/viewer/viewer-example.tsx React wrapper that lazy-mounts Angular viewer demo inside docs.
website/src/content/docs/angular/code-examples/viewer/ui-customization-example.tsx React wrapper that lazy-mounts Angular UI customization demo.
website/src/content/docs/angular/code-examples/viewer/theme-example.tsx React wrapper that lazy-mounts Angular theme demo.
website/src/content/docs/angular/code-examples/viewer/spread-example.tsx React wrapper that lazy-mounts Angular spread demo.
website/src/content/docs/angular/code-examples/viewer/signature-example.tsx React wrapper that lazy-mounts Angular signature demo.
website/src/content/docs/angular/code-examples/viewer/selection-example.tsx React wrapper that lazy-mounts Angular selection demo.
website/src/content/docs/angular/code-examples/viewer/scroll-example.tsx React wrapper that lazy-mounts Angular scroll demo.
website/src/content/docs/angular/code-examples/viewer/rotate-example.tsx React wrapper that lazy-mounts Angular rotate demo.
website/src/content/docs/angular/code-examples/viewer/print-example.tsx React wrapper that lazy-mounts Angular print demo.
website/src/content/docs/angular/code-examples/viewer/pan-example.tsx React wrapper that lazy-mounts Angular pan demo.
website/src/content/docs/angular/code-examples/viewer/i18n-example.tsx React wrapper that lazy-mounts Angular i18n demo.
website/src/content/docs/angular/code-examples/viewer/form-example.tsx React wrapper that lazy-mounts Angular form demo.
website/src/content/docs/angular/code-examples/viewer/export-example.tsx React wrapper that lazy-mounts Angular export demo.
website/src/content/docs/angular/code-examples/viewer/engine-example.tsx React wrapper that lazy-mounts Angular engine demo.
website/src/content/docs/angular/code-examples/viewer/document-manager-example.tsx React wrapper that lazy-mounts Angular doc-manager demo.
website/src/content/docs/angular/code-examples/viewer/annotation-example.tsx React wrapper that lazy-mounts Angular annotation demo.
website/src/content/docs/angular/code-examples/use-angular-mount.tsx Implements lazy client-side Angular mounting inside Next.js docs.
website/src/content/docs/angular/_meta.ts Adds Angular docs section navigation metadata.
website/src/content/docs/_meta.ts Adds Angular as a top-level docs page.
website/src/content/_meta.ts Adds /angular-pdf-viewer page metadata.
website/src/components/logos/index.tsx Adds Angular ecosystem logos (Angular Material, PrimeNG, Spartan/ng).
website/src/components/homepage.tsx Adds Angular to homepage hero, framework paths, and headless section CTA.
website/src/components/homepage-framework-links.ts Extracts framework CTA link/text mapping helpers (now includes Angular).
website/src/components/homepage-framework-links.test.ts Adds unit tests for Angular CTA mapping.
website/src/components/framework-icons.tsx Adds AngularIcon and uses useId for SVG gradient uniqueness.
website/src/components/framework-cards.tsx Adds Angular card and updates grid layout.
website/src/app/angular-pdf-viewer/page.tsx Adds the Angular marketing landing page route.
website/src/tests/angular-helper-docs.test.ts Adds docs-lint test for Angular helper-signal invocation patterns.
website/package.json Adds Angular deps and adds a test script for website tests.
vitest.config.ts Adds root Vitest workspace project aggregator.
viewers/angular/vitest.config.ts Adds Angular package jsdom-mode Vitest configuration.
viewers/angular/vitest.browser.config.ts Adds Angular package browser-mode (Playwright) Vitest configuration.
viewers/angular/vite.config.ts Adds Vite build config for the Angular viewer package.
viewers/angular/tsconfig.json Adds strict TS/Angular compiler config for the Angular package.
viewers/angular/src/test-setup.ts Sets up Analog/Vitest Angular TestBed with zoneless + teardown.
viewers/angular/src/smoke.browser.spec.ts Adds real Chromium smoke test for Angular PDFViewer boot.
viewers/angular/src/plugin-signals.ts Adds signal helpers to derive plugin capabilities and document scopes.
viewers/angular/src/plugin-signals.spec.ts Adds unit tests for the signal helper utilities.
viewers/angular/src/pdf-viewer.config.ts Adds default-config injection token and deep-merge provider helpers.
viewers/angular/src/pdf-viewer.config.spec.ts Tests deep-merge behavior and prototype-pollution defenses.
viewers/angular/src/pdf-viewer.component.ts Implements <embedpdf-viewer> Angular wrapper around @embedpdf/snippet.
viewers/angular/src/index.ts Exports the Angular public surface (re-exports snippet + Angular helpers).
viewers/angular/src/index.test-d.ts Adds type-level contract tests for the public surface.
viewers/angular/package.json Adds new @embedpdf/angular-pdf-viewer package metadata/scripts/deps.
turbo.json Adds test, test:browser, and e2e tasks and dependency wiring.
pnpm-workspace.yaml Excludes .vercel directories under examples from workspace globs.
packages/vitest-config/tsconfig.json Adds TS config for shared Vitest config package.
packages/vitest-config/src/node.ts Adds reusable Node-mode Vitest config helper.
packages/vitest-config/src/angular-jsdom.ts Adds reusable Angular jsdom-mode Vitest config helper.
packages/vitest-config/src/angular-browser.ts Adds reusable Angular browser-mode Vitest config helper.
packages/vitest-config/package.json Adds @embedpdf/vitest-config package exports/peerDeps.
packages/models/vitest.config.ts Adds Vitest config for @embedpdf/models.
packages/models/tsconfig.json Switches test globals typing from Jest to Vitest.
packages/models/src/task.test.ts Migrates task tests from Jest mocks to Vitest vi.
packages/models/src/logger.test.ts Migrates logger tests from Jest mocks to Vitest vi.
packages/models/package.json Adds Vitest scripts/deps and removes Jest dependencies.
packages/build/vitest.config.ts Adds Vitest config for @embedpdf/build tests.
packages/build/test/validate-package-exports.test.ts Adds unit tests for the exports-map validator plugin.
packages/build/test/fixtures/pure-reexport/vite.config.ts Adds fixture to reproduce pure re-export DTS emission scenario.
packages/build/test/fixtures/pure-reexport/tsconfig.json Adds TS config for pure re-export fixture.
packages/build/test/fixtures/pure-reexport/src/index.ts Adds pure export * fixture entrypoint.
packages/build/test/fixtures/pure-reexport/package.json Adds package metadata for pure re-export fixture.
packages/build/test/dts-emission.test.ts Adds regression test to ensure DTS output for pure re-export entries.
packages/build/src/vite/validate-package-exports.ts Adds build-time validator ensuring advertised exports exist/non-empty.
packages/build/src/vite/index.ts Adds angular mode to defineLibrary, adds validator, and hardens DTS emission.
packages/build/package.json Adds Vitest scripts/deps and Angular plugin dependency/peerDep.
package.json Adds new root scripts for Angular dev/e2e/testing and adds Vitest dep.
examples/angular-tailwind/vite.lib.config.ts Adds library build for exporting docs-mountable Angular demos.
examples/angular-tailwind/vite.config.ts Adds Vite config for Angular Tailwind demo shell.
examples/angular-tailwind/tsconfig.lib.json Adds TS config for the examples library build output.
examples/angular-tailwind/tsconfig.json Adds TS config for Angular Tailwind workspace.
examples/angular-tailwind/src/styles.css Adds Tailwind + base styles for Angular Tailwind demo.
examples/angular-tailwind/src/main.ts Bootstraps Angular Tailwind demo with zoneless CD.
examples/angular-tailwind/src/examples/viewer/zoom-example.ts Adds Angular zoom demo implementation.
examples/angular-tailwind/src/examples/viewer/viewer-example.ts Adds minimal Angular viewer demo implementation.
examples/angular-tailwind/src/examples/viewer/ui-customization-example.ts Adds Angular runtime toolbar/schema customization demo.
examples/angular-tailwind/src/examples/viewer/theme-example.ts Adds Angular theme accent customization demo.
examples/angular-tailwind/src/examples/viewer/spread-example.ts Adds Angular spread mode demo.
examples/angular-tailwind/src/examples/viewer/selection-example.ts Adds Angular selection/copy demo.
examples/angular-tailwind/src/examples/viewer/scroll-initial-page-example.ts Adds Angular “scroll to page on layout ready” demo.
examples/angular-tailwind/src/examples/viewer/scroll-example.ts Adds Angular page navigation demo (prev/next).
examples/angular-tailwind/src/examples/viewer/rotate-example.ts Adds Angular rotate demo.
examples/angular-tailwind/src/examples/viewer/print-example.ts Adds Angular print demo.
examples/angular-tailwind/src/examples/viewer/pan-example.ts Adds Angular pan/hand-tool demo.
examples/angular-tailwind/src/examples/viewer/i18n-example.ts Adds Angular locale switching demo.
examples/angular-tailwind/src/examples/viewer/form-example.ts Adds Angular forms state demo.
examples/angular-tailwind/src/examples/viewer/export-example.ts Adds Angular export/download + simulated save demo.
examples/angular-tailwind/src/examples/viewer/engine-example.ts Adds Angular engine-inspection demo using resource().
examples/angular-tailwind/src/examples/viewer/disable-categories-example.ts Adds Angular disabled-categories demo.
examples/angular-tailwind/src/examples/viewer/annotation-example.ts Adds Angular annotation tool selection demo.
examples/angular-tailwind/src/example-support.ts Adds shared signals/theme helpers for Angular Tailwind demos.
examples/angular-tailwind/README.md Documents purpose and usage of Angular Tailwind workspace.
examples/angular-tailwind/playwright.config.ts Adds Playwright config for Angular Tailwind workspace.
examples/angular-tailwind/package.json Adds Angular Tailwind workspace package metadata/scripts/deps.
examples/angular-tailwind/index.html Adds HTML entry for Angular Tailwind demo.
examples/angular-tailwind/e2e/viewer-demos.spec.ts Adds E2E coverage for non-trivial Angular Tailwind demos.
examples/angular-pdf-viewer/vite.config.ts Adds Vite config for consumer-style Angular PDF viewer demo.
examples/angular-pdf-viewer/tsconfig.json Adds TS config for Angular PDF viewer demo.
examples/angular-pdf-viewer/src/styles.css Adds base styles for full-height demo layout.
examples/angular-pdf-viewer/src/main.ts Bootstraps consumer demo with zoneless CD + default viewer providers.
examples/angular-pdf-viewer/src/app/viewer-config.ts Adds theme/default config constants for demo app.
examples/angular-pdf-viewer/README.md Documents purpose and usage of Angular consumer demo workspace.
examples/angular-pdf-viewer/playwright.config.ts Adds Playwright config for Angular consumer demo.
examples/angular-pdf-viewer/package.json Adds Angular consumer demo package metadata/scripts/deps.
examples/angular-pdf-viewer/index.html Adds HTML entry for Angular consumer demo.
examples/angular-pdf-viewer/e2e/viewer.spec.ts Adds E2E coverage for theme/category/runtime toolbar customization.
examples/angular-pdf-viewer/.gitignore Ignores Playwright output for Angular consumer demo.
.gitignore Expands ignores for coverage/Playwright/Vercel/etc. (currently duplicated entries).
.github/workflows/test.yml Adds CI workflow for Node-mode tests and conditional Angular browser-mode tests.
.changeset/config.json Adds Angular example packages to changeset ignore list.
.changeset/angular-pdf-viewer-initial.md Adds changeset for initial @embedpdf/angular-pdf-viewer release.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread website/src/components/homepage-framework-links.ts
The Ult and others added 2 commits May 14, 2026 13:12
Fail loudly for unexpected runtime values and preserve compile-time exhaustiveness if the Framework union grows.

Add focused tests and inline docs so the pattern stays clear for future edits.

Co-Authored-By: GitHub Copilot <copilot@github.com>
Add Angular-specific CI coverage for formatting, linting, builds, browser tests, and example e2e runs. Keep the workflow path-filtered so Angular regressions fail fast without dragging unrelated monorepo debt into every pull request.

Add project-local ESLint configs and small Angular example cleanups so the new quality gates pass with the current Angular wrapper and demos.

Co-Authored-By: GitHub Copilot <noreply@github.com>
@the-ult the-ult marked this pull request as draft May 15, 2026 09:46
@the-ult
Copy link
Copy Markdown
Author

the-ult commented May 15, 2026

I put it back to draft. First want to make sure that the published packages are properly working. Since the setup using vite is different from Angular's normal APF (Angular Packaging Format)

Build the Angular viewer as an APF package with ng-packagr so the
published artifact uses partial compilation and ships the expected
fesm2022/types layout.

Keep the Analog/Vite path for local development, but make it fail fast
on type issues and add a pack/install/build smoke test so CI verifies
the published tarball instead of only workspace linking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@the-ult the-ult marked this pull request as ready for review May 15, 2026 12:21
The Ult and others added 2 commits May 15, 2026 14:32
Rename the single-example Playwright install step in test-angular-e2e to
install Chromium for both examples explicitly; both use only Chromium so
the second call is a fast no-op, but the dependency is now self-documenting
rather than implicit.

Add a comment above FRAMEWORK_PREFIXES in validate-package-exports.ts
pointing maintainers to the matching defineLibrary() switch so the list
stays in sync when new framework modes are added.
Angular CLI 21 validates the project name passed to ng new, so the
workflow can no longer pass a filesystem path as the first argument.

Create the temporary consumer app from inside the mktemp directory so
the smoke test still exercises the packed Angular viewer install and
build flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@the-ult
Copy link
Copy Markdown
Author

the-ult commented May 17, 2026

@bobsingor is there anything you'll need from me? Before you can review?

The Ult and others added 3 commits May 17, 2026 22:13
Build the viewer workspace before starting the Angular example Playwright
web servers. The examples import the Angular viewer through its dist
entry points, so a fresh checkout cannot boot the app until those
artifacts exist.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Run the viewer build in the Angular examples e2e job before the
Playwright web servers start. The previous change landed in the
browser-only job, which left the failing fresh-checkout example path
unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Only run the Angular example screenshot assertions when the current
platform already has a checked-in baseline. This keeps the semantic e2e
coverage in Linux CI while avoiding hard failures from missing platform
snapshot files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants