import * as _angular_core from '@angular/core';
import { OnDestroy, InjectionToken, ElementRef } from '@angular/core';
/**
* Shape descriptor accepted by SdPreviewImage's `items` signal input.
*
* - `string` — CDN/HTTP URL; component will fetch as blob and create a File.
* - `File` — already-selected file from . Must be `image/*`.
* - Detailed object — when the caller wants to override name/caption/alt.
*/
type PreviewItem = string | File | {
url?: string;
file?: File;
name?: string;
caption?: string;
alt?: string;
mime?: string;
};
/**
* Internal normalized record. One per slot in the gallery.
* `blobUrl` is always set after a successful load so the
binding can
* be uniform; `url` retains the original CDN URL for download fallback.
*/
interface NormalizedImage {
id: string;
url?: string;
blobUrl: string;
name: string;
size: number;
caption?: string;
alt?: string;
loading: boolean;
error: boolean;
}
/**
* Stage = the visual state of the main image area inside the viewer shell.
* Driven by an internal `_stage` signal in the component.
*/
type PreviewStage = 'ready' | 'loading' | 'error' | 'empty';
/**
* Where the thumbnail navigator sits relative to the stage. `none` removes
* thumbnails entirely (single-image lightbox); `dots` swaps the strip for
* compact dot indicators (≤ 8 images).
*/
type ThumbnailPosition = 'bottom' | 'right' | 'left' | 'top' | 'dots' | 'none';
/**
* Color scheme for the preview shell. `'dark'` (default) keeps the original
* dark-theme tokens (black surfaces, white text). `'light'` flips the token
* set to white surfaces / dark text — picks up `--sd-primary`, `--sd-error`,
* `--sd-success` from the consumer theme when present.
*
* Exposed via `[attr.data-theme]` on the host so SCSS can swap CSS custom
* properties via the `:host([data-theme="light"])` selector — no runtime
* style switching is required.
*/
type PreviewTheme = 'dark' | 'light';
declare class SdPreviewImage implements OnDestroy {
#private;
static readonly MIN_ZOOM = 0.25;
static readonly MAX_ZOOM = 4;
static readonly ZOOM_STEP = 0.1;
static readonly SWIPE_THRESHOLD = 40;
readonly autoIdInput: _angular_core.InputSignal;
readonly autoId: _angular_core.Signal;
readonly autoIdPrev: _angular_core.Signal;
readonly autoIdNext: _angular_core.Signal;
readonly autoIdZoomIn: _angular_core.Signal;
readonly autoIdZoomOut: _angular_core.Signal;
readonly autoIdFit: _angular_core.Signal;
readonly autoIdRotate: _angular_core.Signal;
readonly autoIdDownload: _angular_core.Signal;
readonly autoIdFullscreen: _angular_core.Signal;
readonly autoIdRetry: _angular_core.Signal;
readonly autoIdThumb: (i: number) => string | undefined;
readonly autoIdDot: (i: number) => string | undefined;
readonly items: _angular_core.InputSignal;
readonly title: _angular_core.InputSignal;
readonly thumbnailPosition: _angular_core.InputSignal;
readonly showToolbar: _angular_core.InputSignal;
readonly downloadable: _angular_core.InputSignal;
readonly zoomable: _angular_core.InputSignal;
readonly loop: _angular_core.InputSignal;
readonly startIndex: _angular_core.InputSignal;
readonly theme: _angular_core.InputSignal;
readonly close: _angular_core.OutputEmitterRef;
readonly activeIndexChange: _angular_core.OutputEmitterRef;
readonly download: _angular_core.OutputEmitterRef<{
index: number;
item: NormalizedImage;
}>;
readonly imageError: _angular_core.OutputEmitterRef<{
index: number;
reason: string;
}>;
readonly activeIndex: _angular_core.Signal;
readonly images: _angular_core.Signal;
readonly zoom: _angular_core.Signal;
readonly rotation: _angular_core.Signal;
readonly pan: _angular_core.Signal<{
x: number;
y: number;
}>;
readonly stage: _angular_core.Signal;
readonly isFullscreen: _angular_core.Signal;
readonly activeImage: _angular_core.Signal;
readonly hasPrev: _angular_core.Signal;
readonly hasNext: _angular_core.Signal;
readonly zoomPercent: _angular_core.Signal;
readonly imageTransform: _angular_core.Signal;
readonly shellClass: _angular_core.Signal<{
[x: string]: boolean;
'sd-preview-shell': boolean;
'sd-preview-shell--fullscreen': boolean;
}>;
constructor();
ngOnDestroy(): void;
onClickThumbnailImage(index: number): void;
updateCurrentImage(direction: 1 | -1): void;
zoomIn(): void;
zoomOut(): void;
fitToScreen(): void;
rotate(direction: 'left' | 'right'): void;
downloadCurrent(): void;
toggleFullscreen(): void;
/** Retry just the active image (Artboard G action). */
retryActive(): Promise;
/** User clicked the X button — emit close intent for the consumer to react. */
requestClose(): void;
onKeyDown(event: KeyboardEvent): void;
onWheel(event: WheelEvent): void;
onPointerDown(event: PointerEvent): void;
onPointerMove(event: PointerEvent): void;
onPointerUp(event: PointerEvent): void;
onPointerCancel(event: PointerEvent): void;
onImageDblClick(): void;
onImageError(): void;
trackByImage(_i: number, item: NormalizedImage): string;
formatBytes(bytes: number): string;
static ɵfac: _angular_core.ɵɵFactoryDeclaration;
static ɵcmp: _angular_core.ɵɵComponentDeclaration;
}
/**
* Source descriptor accepted by SdPreviewPdf's `source` signal input.
*
* Mirrors the input shapes that `pdfjsLib.getDocument()` understands while
* adding consumer-friendly variants (raw `File`/`Blob`). The component handles
* the bridging internally — caller never touches pdfjs types.
*/
type PdfSource = string | File | Blob | ArrayBuffer | Uint8Array | {
url: string;
httpHeaders?: Record;
withCredentials?: boolean;
} | {
data: ArrayBuffer | Uint8Array;
};
/**
* Zoom expressed either as a raw scale number (1 = 100%) OR a symbolic mode
* that auto-fits the stage. The auto modes recompute on container resize +
* page change.
*/
type PdfZoomMode = number | 'page-fit' | 'page-width' | 'page-actual';
/** Which tab the sidebar shows. `'none'` collapses the sidebar entirely. */
type PdfSidebarMode = 'thumbnails' | 'outline' | 'search' | 'none';
/** Page layout mode. */
type PdfScrollMode = 'page' | 'continuous';
/** Consumer-facing, recursively resolved PDF document-outline item. */
interface PdfOutlineItem {
readonly id: string;
readonly title: string;
readonly page: number | null;
readonly url?: string;
readonly children: readonly PdfOutlineItem[];
}
/**
* Document-level metadata extracted from `pdfDoc.getMetadata()`.
*/
interface PdfMeta {
title?: string;
author?: string;
subject?: string;
numPages: number;
}
/** Visual state of the stage. */
type PdfStage = 'empty' | 'loading' | 'ready' | 'error';
/** Classifier for `loadError` output — drives which Artboard H copy renders. */
type PdfErrorReason = 'invalid' | 'password' | 'network' | 'unknown';
/** Fired once after `getDocument()` resolves successfully. */
interface PdfLoadEvent {
totalPages: number;
meta: PdfMeta;
}
/** Fired whenever a load attempt rejects. */
interface PdfErrorEvent {
reason: PdfErrorReason;
message?: string;
}
/**
* One hit returned by `SdPreviewPdf.search()`. `before` / `term` / `after`
* are sliced from the original page text so the result list can render a
* snippet with the matched substring wrapped in `` while preserving the
* surrounding context (~30 chars each side).
*
* `textItemIndices` is reserved for the in-page highlight pass — it carries
* the indices of the pdfjs text items the match spans across so the renderer
* can wrap the right spans without re-running the search per page.
*/
interface PdfSearchResult {
page: number;
before: string;
term: string;
after: string;
textItemIndices?: number[];
}
/**
* Lightweight projection of the internal search state for the
* `searchChange` output + the result-list rendering. `activeIndex` is `-1`
* when no result is currently focused (e.g. immediately after a `clearSearch`).
*/
interface PdfSearchState {
term: string;
caseSensitive: boolean;
wholeWord: boolean;
results: PdfSearchResult[];
activeIndex: number;
truncated: boolean;
}
interface SdPdfRenderTask {
readonly promise: Promise;
cancel(): void;
}
interface SdPdfViewport {
readonly width: number;
readonly height: number;
}
interface SdPdfTextItem {
readonly str: string;
}
interface SdPdfTextContent {
readonly items: readonly unknown[];
}
interface SdPdfPageProxy {
getViewport(parameters: {
scale: number;
rotation?: number;
}): SdPdfViewport;
render(parameters: {
canvasContext: CanvasRenderingContext2D;
viewport: SdPdfViewport;
}): SdPdfRenderTask;
getTextContent(): Promise;
cleanup(): void;
}
interface SdPdfReference {
readonly num: number;
readonly gen: number;
}
type SdPdfDestination = string | readonly unknown[] | null;
interface SdPdfRawOutlineItem {
readonly title?: string;
readonly dest?: SdPdfDestination;
readonly url?: string | null;
readonly items?: readonly SdPdfRawOutlineItem[];
}
interface SdPdfDocumentProxy {
readonly numPages: number;
getPage(pageNumber: number): Promise;
getMetadata(): Promise<{
readonly info?: {
readonly Title?: string;
readonly Author?: string;
readonly Subject?: string;
};
}>;
getOutline(): Promise;
getDestination(name: string): Promise;
getPageIndex(reference: SdPdfReference): Promise;
cachedPageNumber(reference: SdPdfReference): number | null;
getData(): Promise;
destroy(): Promise;
}
interface SdPdfLoadingTask {
readonly promise: Promise;
onProgress?: (progress: {
loaded: number;
total: number;
}) => void;
destroy?(): Promise | void;
}
interface SdPdfDocumentSpec {
url?: string;
data?: Uint8Array;
httpHeaders?: Record;
withCredentials?: boolean;
password?: string;
}
interface SdPdfJsLib {
getDocument(spec: SdPdfDocumentSpec): SdPdfLoadingTask;
readonly GlobalWorkerOptions: {
workerSrc: string;
};
}
declare const SD_PDFJS_LIB: InjectionToken;
interface PdfOutlineRow {
readonly item: PdfOutlineItem;
readonly level: number;
readonly parentId: string | null;
}
type PdfSidebarTabMode = Exclude;
declare class SdPreviewPdf {
#private;
static readonly MIN_ZOOM = 0.25;
static readonly MAX_ZOOM = 4;
static readonly ZOOM_STEP = 0.1;
static readonly OUTLINE_MAX_DEPTH = 64;
static readonly OUTLINE_MAX_NODES = 10000;
static readonly MAX_SEARCH_RESULTS = 1000;
static readonly MAX_PAGE_TEXT_CACHE_PAGES = 128;
static readonly THUMBNAIL_WINDOW_SIZE = 48;
static readonly THUMBNAIL_ITEM_HEIGHT = 220;
static readonly MAX_THUMBNAIL_CACHE_ENTRIES = 96;
private static readonly MAX_CONCURRENT_THUMBNAIL_WORK;
static readonly MAX_CANVAS_DIMENSION = 8192;
static readonly MAX_CANVAS_PIXELS = 16777216;
protected readonly pageCanvasRef: _angular_core.Signal | undefined>;
protected readonly stageEl: _angular_core.Signal | undefined>;
protected readonly pageInputRef: _angular_core.Signal | undefined>;
protected readonly searchInputRef: _angular_core.Signal | undefined>;
protected readonly sidebarContentRef: _angular_core.Signal | undefined>;
protected readonly outlineItemRefs: _angular_core.Signal[]>;
protected readonly sidebarTabRefs: _angular_core.Signal[]>;
protected readonly continuousCanvases: _angular_core.Signal[]>;
protected readonly thumbCanvases: _angular_core.Signal[]>;
readonly autoIdInput: _angular_core.InputSignal;
readonly autoId: _angular_core.Signal;
readonly autoIdFirst: _angular_core.Signal;
readonly autoIdPrev: _angular_core.Signal;
readonly autoIdNext: _angular_core.Signal;
readonly autoIdLast: _angular_core.Signal;
readonly autoIdPageInput: _angular_core.Signal;
readonly autoIdZoomIn: _angular_core.Signal;
readonly autoIdZoomOut: _angular_core.Signal;
readonly autoIdZoomReadout: _angular_core.Signal;
readonly autoIdFitPage: _angular_core.Signal;
readonly autoIdFitWidth: _angular_core.Signal;
readonly autoIdRotate: _angular_core.Signal;
readonly autoIdScrollMode: _angular_core.Signal;
readonly autoIdSearchToggle: _angular_core.Signal;
readonly autoIdPrint: _angular_core.Signal;
readonly autoIdDownload: _angular_core.Signal;
readonly autoIdFullscreen: _angular_core.Signal;
readonly autoIdSidebarToggle: _angular_core.Signal;
readonly autoIdTabThumbnails: _angular_core.Signal;
readonly autoIdTabOutline: _angular_core.Signal;
readonly autoIdTabSearch: _angular_core.Signal;
readonly sidebarPanelId: _angular_core.Signal;
readonly sidebarRegionId: _angular_core.Signal;
readonly searchBarId: _angular_core.Signal;
readonly tabThumbnailsId: _angular_core.Signal;
readonly tabOutlineId: _angular_core.Signal;
readonly tabSearchId: _angular_core.Signal;
readonly sidebarActiveTabId: _angular_core.Signal;
readonly autoIdSearchInput: _angular_core.Signal;
readonly autoIdSearchNext: _angular_core.Signal;
readonly autoIdSearchPrev: _angular_core.Signal;
readonly autoIdSearchCase: _angular_core.Signal;
readonly autoIdSearchWhole: _angular_core.Signal;
readonly autoIdSearchClose: _angular_core.Signal;
readonly autoIdRetry: _angular_core.Signal;
readonly autoIdThumb: (i: number) => string | undefined;
readonly autoIdResult: (i: number) => string | undefined;
readonly source: _angular_core.InputSignal;
readonly title: _angular_core.InputSignal;
readonly startPage: _angular_core.InputSignal;
readonly initialZoom: _angular_core.InputSignal;
readonly sidebar: _angular_core.InputSignal;
readonly sidebarOpen: _angular_core.InputSignal;
readonly scrollMode: _angular_core.InputSignal;
readonly showToolbar: _angular_core.InputSignal;
readonly downloadable: _angular_core.InputSignal;
readonly password: _angular_core.InputSignal;
readonly httpHeaders: _angular_core.InputSignal | undefined>;
readonly theme: _angular_core.InputSignal;
readonly close: _angular_core.OutputEmitterRef;
readonly loaded: _angular_core.OutputEmitterRef;
readonly pageChange: _angular_core.OutputEmitterRef;
readonly zoomChange: _angular_core.OutputEmitterRef;
readonly download: _angular_core.OutputEmitterRef<{
filename: string;
}>;
readonly loadError: _angular_core.OutputEmitterRef;
readonly searchChange: _angular_core.OutputEmitterRef<{
term: string;
total: number;
current: number;
truncated: boolean;
}>;
readonly stage: _angular_core.Signal;
readonly activePage: _angular_core.Signal;
readonly zoom: _angular_core.Signal;
readonly zoomMode: _angular_core.Signal;
readonly rotation: _angular_core.Signal;
readonly sidebarMode: _angular_core.Signal;
readonly scrollModeCurrent: _angular_core.Signal;
readonly isFullscreen: _angular_core.Signal;
readonly meta: _angular_core.Signal;
readonly filename: _angular_core.Signal;
readonly fileSize: _angular_core.Signal;
readonly loadError$: _angular_core.Signal;
readonly thumbCache: _angular_core.Signal>;
readonly thumbnailWorkCount: _angular_core.Signal;
readonly pageTextCacheSize: _angular_core.Signal;
readonly continuousPages: _angular_core.Signal;
readonly continuousTopSpacer: _angular_core.Signal;
readonly continuousBottomSpacer: _angular_core.Signal;
readonly continuousPageHeights: _angular_core.Signal>;
readonly outline: _angular_core.Signal;
readonly outlineFocusId: _angular_core.Signal;
readonly visibleOutline: _angular_core.Signal;
readonly numPages: _angular_core.Signal;
readonly canPrev: _angular_core.Signal;
readonly canNext: _angular_core.Signal;
readonly zoomPercent: _angular_core.Signal;
readonly loadPercent: _angular_core.Signal;
readonly isSidebarOpen: _angular_core.Signal;
readonly canDownload: _angular_core.Signal;
readonly canFullscreen: _angular_core.Signal;
readonly canPrint: _angular_core.Signal;
readonly pageList: _angular_core.Signal;
readonly pageNumbers: _angular_core.Signal;
readonly thumbnailTopSpacer: _angular_core.Signal;
readonly thumbnailBottomSpacer: _angular_core.Signal;
readonly searchBarOpen: _angular_core.Signal;
readonly searchTerm: _angular_core.Signal;
readonly searchResults: _angular_core.Signal;
readonly searchActiveIndex: _angular_core.Signal;
readonly searchCaseSensitive: _angular_core.Signal;
readonly searchWholeWord: _angular_core.Signal;
readonly searchTotal: _angular_core.Signal;
readonly searchTruncated: _angular_core.Signal;
readonly searchCurrent: _angular_core.Signal;
readonly searchActiveResult: _angular_core.Signal;
readonly searchState: _angular_core.Signal;
constructor();
goToPage(page: number): void;
nextPage(): void;
prevPage(): void;
firstPage(): void;
lastPage(): void;
zoomIn(): void;
zoomOut(): void;
setZoom(mode: PdfZoomMode): void;
rotate(direction: 'left' | 'right'): void;
toggleSidebar(): void;
setSidebarMode(mode: PdfSidebarMode): void;
onSidebarTabKeyDown(event: KeyboardEvent, currentMode: PdfSidebarTabMode): void;
onThumbnailSidebarScroll(event: Event): void;
setScrollMode(mode: PdfScrollMode): void;
downloadFile(): void;
downloadFileAsync(): Promise;
toggleFullscreen(): void;
/** Programmatic equivalent of clicking the X — emits the close output. */
requestClose(): void;
/** Retry the active load attempt (called from the error state retry button). */
retryLoad(): void;
printFile(): void;
print(): Promise;
isOutlineExpanded(id: string): boolean;
toggleOutlineItem(id: string, event?: Event): void;
focusOutlineItem(id: string): void;
activateOutlineItem(id: string): void;
onOutlineKeyDown(event: KeyboardEvent, id: string): void;
/**
* Run a full-document search for `term`. Returns the result count.
*
* Options:
* - `caseSensitive`: default off; matches independent of capitalisation.
* - `wholeWord`: default off; requires Unicode word-boundary on both sides
* so `cat` does NOT match `category` (uses `/\b...\b/u` so Vietnamese
* diacritic-bearing letters still participate as word characters).
*
* Implementation: iterate every page once (cached), build a flat plain-text
* string per page (joining textItem.str), and slice ~30 chars of context
* around each match. We deliberately use plain JS regex rather than
* pdf.js's `pdfFindController` — it's <40 lines, fully testable, and
* sidesteps the find-controller's dependency on a real text layer (which
* we don't render).
*/
search(term: string, options?: {
caseSensitive?: boolean;
wholeWord?: boolean;
}): Promise;
searchNext(): void;
searchPrev(): void;
activateSearchResult(index: number): void;
clearSearch(): void;
/** Open the search bar and focus its input. Idempotent. */
openSearch(): void;
/** Close the search bar AND clear results (mirrors Acrobat behaviour). */
closeSearch(): void;
toggleSearchCaseSensitive(): void;
toggleSearchWholeWord(): void;
/** Live binding from the search bar's `(input)` event. */
onSearchInput(event: Event): void;
onKeyDown(event: KeyboardEvent): void;
onPageInputEnter(event: Event): void;
onPageInputBlur(event: Event): void;
onWheel(event: WheelEvent): void;
trackByPage(_i: number, page: number): number;
onStageScroll(): void;
/**
* Render a single page into a sidebar thumbnail canvas at ~140px width.
* Reserved in `#thumbnailWork` before getPage() so rapid scroll bounces
* cannot start duplicate work for the same mounted page.
*
* Visible for testing — tests can stub `getPage()` on the fake doc to
* assert this method calls `render(...)` with the right page argument.
*/
renderThumbnailForPage(pageNum: number): Promise;
static ɵfac: _angular_core.ɵɵFactoryDeclaration;
static ɵcmp: _angular_core.ɵɵComponentDeclaration;
}
interface SdPdfIntersectionEntry {
readonly target: Element;
readonly isIntersecting: boolean;
}
interface SdPdfBrowserAdapter {
readonly isBrowser: boolean;
/** The platform can trigger an anchor download for an existing URL. */
readonly canDownloadUrl: boolean;
/** The platform can create/revoke an object URL and then download it. */
readonly canDownloadBlob: boolean;
readonly canFullscreen: boolean;
isFile(value: unknown): value is File;
isBlob(value: unknown): value is Blob;
createPdfBlob(data: Uint8Array): Blob | null;
createObjectUrl(blob: Blob): string | null;
revokeObjectUrl(url: string): void;
download(href: string, filename: string): boolean;
createElement(tagName: K): HTMLElementTagNameMap[K] | null;
createImage(): HTMLImageElement | null;
listenFullscreen(host: HTMLElement, listener: (active: boolean) => void): () => void;
toggleFullscreen(host: HTMLElement): Promise;
observeResize(element: Element, listener: () => void): () => void;
observeIntersections(elements: readonly Element[], listener: (entries: readonly SdPdfIntersectionEntry[]) => void, options?: IntersectionObserverInit): () => void;
scheduleFrame(callback: FrameRequestCallback): number | null;
cancelFrame(handle: number | null): void;
}
declare const SD_PDF_BROWSER_ADAPTER: InjectionToken;
interface SdPdfPrintJob {
readonly finished: Promise;
cancel(): void;
}
interface SdPdfPrintAdapter {
readonly isSupported: boolean;
start(data: Uint8Array, filename: string): SdPdfPrintJob | null;
}
declare const SD_PDF_PRINT_ADAPTER: InjectionToken;
export { SD_PDFJS_LIB, SD_PDF_BROWSER_ADAPTER, SD_PDF_PRINT_ADAPTER, SdPreviewImage, SdPreviewPdf };
export type { NormalizedImage, PdfErrorEvent, PdfErrorReason, PdfLoadEvent, PdfMeta, PdfOutlineItem, PdfScrollMode, PdfSearchResult, PdfSearchState, PdfSidebarMode, PdfSource, PdfStage, PdfZoomMode, PreviewItem, PreviewStage, PreviewTheme, SdPdfBrowserAdapter, SdPdfDestination, SdPdfDocumentProxy, SdPdfDocumentSpec, SdPdfIntersectionEntry, SdPdfJsLib, SdPdfLoadingTask, SdPdfPageProxy, SdPdfPrintAdapter, SdPdfPrintJob, SdPdfRawOutlineItem, SdPdfReference, SdPdfRenderTask, SdPdfTextContent, SdPdfTextItem, SdPdfViewport, ThumbnailPosition };