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 };