Skip to content

Commit

Permalink
Convert to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmaj committed Apr 17, 2023
1 parent 1796be3 commit e93a356
Show file tree
Hide file tree
Showing 27 changed files with 675 additions and 182 deletions.
6 changes: 4 additions & 2 deletions __mocks__/_failing_page.js → __mocks__/_failing_page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { PDFPageProxy } from 'pdfjs-dist';

export default {
cleanup: () => {
// Intentionally empty
return true;
},
commonObjs: {
get: () => {
Expand All @@ -21,4 +23,4 @@ export default {
// Intentionally empty
},
}),
};
} as unknown as PDFPageProxy;
4 changes: 3 additions & 1 deletion __mocks__/_failing_pdf.js → __mocks__/_failing_pdf.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { PDFDocumentProxy } from 'pdfjs-dist';

export default {
_pdfInfo: {
fingerprint: 'a62067476e69734bb8eb60122615dfbf',
Expand All @@ -7,4 +9,4 @@ export default {
getOutline: () => new Promise((resolve, reject) => reject(new Error())),
getPage: () => new Promise((resolve, reject) => reject(new Error())),
numPages: 4,
};
} as unknown as PDFDocumentProxy;
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { RenderingCancelledException } from 'pdfjs-dist';

import type { PDFDocumentProxy } from 'pdfjs-dist';

export default {
_pdfInfo: {
fingerprint: 'a62067476e69734bb8eb60122615dfbf',
Expand All @@ -18,4 +20,4 @@ export default {
reject(new RenderingCancelledException('Cancelled', 'cancelled')),
),
numPages: 4,
};
} as unknown as PDFDocumentProxy;
111 changes: 99 additions & 12 deletions src/Document.jsx → src/Document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,74 @@ import {
import { useResolver } from './shared/hooks';
import { eventProps, isClassName, isFile, isRef } from './shared/propTypes';

import type { PDFDocumentProxy } from 'pdfjs-dist';
import type {
ClassName,
ExternalLinkRel,
ExternalLinkTarget,
File,
ImageResourcesPath,
NodeOrRenderer,
OnError,
OnItemClickArgs,
OnLoadProgressArgs,
OnPasswordCallback,
Options,
PasswordResponse,
RenderMode,
Source,
} from './shared/types';

const { PDFDataRangeTransport } = pdfjs;

const defaultOnPassword = (callback, reason) => {
type OnItemClick = (args: OnItemClickArgs) => void;

type OnLoadError = OnError;

type OnLoadProgress = (args: OnLoadProgressArgs) => void;

type OnLoadSuccess = (pdf: PDFDocumentProxy) => void;

type OnPassword = (callback: OnPasswordCallback, reason: PasswordResponse) => void;

type OnSourceError = OnError;

type OnSourceSuccess = () => void;

type DocumentProps = {
children?: React.ReactNode;
className?: ClassName;
error?: NodeOrRenderer;
externalLinkRel?: ExternalLinkRel;
externalLinkTarget?: ExternalLinkTarget;
file?: File;
imageResourcesPath?: ImageResourcesPath;
inputRef?: React.Ref<HTMLDivElement>;
loading?: NodeOrRenderer;
noData?: NodeOrRenderer;
onItemClick?: OnItemClick;
onLoadError?: OnLoadError;
onLoadProgress?: OnLoadProgress;
onLoadSuccess?: OnLoadSuccess;
onPassword?: OnPassword;
onSourceError?: OnSourceError;
onSourceSuccess?: OnSourceSuccess;
options?: Options;
renderMode?: RenderMode;
rotate?: number | null;
};

function objectWithoutNull<T>(obj: T): T {
const acc: Partial<T> = {};

for (const key in obj) {
if (obj[key] !== null) acc[key] = obj[key];
}

return acc as T;
}

const defaultOnPassword: OnPassword = (callback, reason) => {
switch (reason) {
case PasswordResponses.NEED_PASSWORD: {
// eslint-disable-next-line no-alert
Expand Down Expand Up @@ -81,21 +146,21 @@ const Document = forwardRef(function Document(
renderMode,
rotate,
...otherProps
},
}: DocumentProps,
ref,
) {
const [sourceState, sourceDispatch] = useResolver();
const [sourceState, sourceDispatch] = useResolver<Source | null>();
const { value: source, error: sourceError } = sourceState;
const [pdfState, pdfDispatch] = useResolver();
const [pdfState, pdfDispatch] = useResolver<PDFDocumentProxy>();
const { value: pdf, error: pdfError } = pdfState;

const linkService = useRef(new LinkService());

const pages = useRef([]);
const pages = useRef<HTMLDivElement[]>([]);

const viewer = useRef({
// Handling jumping to internal links target
scrollPageIntoView: ({ dest, pageIndex, pageNumber }) => {
scrollPageIntoView: ({ dest, pageIndex, pageNumber }: OnItemClickArgs) => {
// First, check if custom handling of onItemClick was provided
if (onItemClick) {
onItemClick({ dest, pageIndex, pageNumber });
Expand Down Expand Up @@ -143,7 +208,12 @@ const Document = forwardRef(function Document(
* Called when a document source failed to be resolved correctly
*/
function onSourceError() {
warning(false, sourceError);
if (!sourceError) {
// Impossible, but TypeScript doesn't know that
return;
}

warning(false, sourceError.toString());

if (onSourceErrorProps) {
onSourceErrorProps(sourceError);
Expand All @@ -156,7 +226,7 @@ const Document = forwardRef(function Document(

useEffect(resetSource, [file, sourceDispatch]);

const findDocumentSource = useCallback(async () => {
const findDocumentSource = useCallback(async (): Promise<Source | null> => {
if (!file) {
return null;
}
Expand Down Expand Up @@ -258,6 +328,11 @@ const Document = forwardRef(function Document(
* Called when a document is read successfully
*/
function onLoadSuccess() {
if (!pdf) {
// Impossible, but TypeScript doesn't know that
return;
}

if (onLoadSuccessProps) {
onLoadSuccessProps(pdf);
}
Expand All @@ -270,7 +345,12 @@ const Document = forwardRef(function Document(
* Called when a document failed to read successfully
*/
function onLoadError() {
warning(false, pdfError);
if (!pdfError) {
// Impossible, but TypeScript doesn't know that
return;
}

warning(false, pdfError.toString());

if (onLoadErrorProps) {
onLoadErrorProps(pdfError);
Expand All @@ -288,7 +368,14 @@ const Document = forwardRef(function Document(
return;
}

const destroyable = pdfjs.getDocument({ ...source, ...options });
const documentInitParams = options
? {
...source,
...objectWithoutNull(options),
}
: source;

const destroyable = pdfjs.getDocument(documentInitParams);
if (onLoadProgress) {
destroyable.onProgress = onLoadProgress;
}
Expand Down Expand Up @@ -343,11 +430,11 @@ const Document = forwardRef(function Document(

useEffect(setupLinkService, [externalLinkRel, externalLinkTarget]);

function registerPage(pageIndex, ref) {
function registerPage(pageIndex: number, ref: HTMLDivElement) {
pages.current[pageIndex] = ref;
}

function unregisterPage(pageIndex) {
function unregisterPage(pageIndex: number) {
delete pages.current[pageIndex];
}

Expand Down
3 changes: 0 additions & 3 deletions src/DocumentContext.jsx

This file was deleted.

5 changes: 5 additions & 0 deletions src/DocumentContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createContext } from 'react';

import type { DocumentContextType } from './shared/types';

export default createContext<DocumentContextType>(null);
48 changes: 37 additions & 11 deletions src/LinkService.js → src/LinkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,43 @@
*/
import invariant from 'tiny-invariant';

import type { PDFDocumentProxy } from 'pdfjs-dist';
import type { Dest, ResolvedDest, ExternalLinkRel, ExternalLinkTarget } from './shared/types';

const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';

type PDFViewer = any;

export default class LinkService {
externalLinkEnabled: boolean;
externalLinkRel?: ExternalLinkRel;
externalLinkTarget?: ExternalLinkTarget;
isInPresentationMode: boolean;
pdfDocument?: PDFDocumentProxy | null;
pdfViewer?: PDFViewer | null;

constructor() {
this.externalLinkTarget = null;
this.externalLinkRel = null;
this.externalLinkEnabled = true;
this.externalLinkRel = undefined;
this.externalLinkTarget = undefined;
this.isInPresentationMode = false;
this.pdfDocument = undefined;
this.pdfViewer = undefined;
}

setDocument(pdfDocument) {
setDocument(pdfDocument: PDFDocumentProxy) {
this.pdfDocument = pdfDocument;
}

setViewer(pdfViewer) {
setViewer(pdfViewer: PDFViewer) {
this.pdfViewer = pdfViewer;
}

setExternalLinkRel(externalLinkRel) {
setExternalLinkRel(externalLinkRel?: ExternalLinkRel) {
this.externalLinkRel = externalLinkRel;
}

setExternalLinkTarget(externalLinkTarget) {
setExternalLinkTarget(externalLinkTarget?: ExternalLinkTarget) {
this.externalLinkTarget = externalLinkTarget;
}

Expand Down Expand Up @@ -62,8 +78,12 @@ export default class LinkService {
// Intentionally empty
}

goToDestination(dest) {
new Promise((resolve) => {
goToDestination(dest: Dest): Promise<void> {
return new Promise<ResolvedDest | null>((resolve) => {
invariant(this.pdfDocument, 'PDF document not loaded.');

invariant(dest, 'Destination is not specified.');

if (typeof dest === 'string') {
this.pdfDocument.getDestination(dest).then(resolve);
} else if (Array.isArray(dest)) {
Expand All @@ -76,7 +96,9 @@ export default class LinkService {

const destRef = explicitDest[0];

new Promise((resolve) => {
new Promise<number>((resolve) => {
invariant(this.pdfDocument, 'PDF document not loaded.');

if (destRef instanceof Object) {
this.pdfDocument
.getPageIndex(destRef)
Expand Down Expand Up @@ -108,15 +130,15 @@ export default class LinkService {
});
}

navigateTo(dest) {
navigateTo(dest: Dest) {
this.goToDestination(dest);
}

goToPage() {
// Intentionally empty
}

addLinkAttributes(link, url, newWindow) {
addLinkAttributes(link: HTMLAnchorElement, url: string, newWindow: boolean) {
link.href = url;
link.rel = this.externalLinkRel || DEFAULT_LINK_REL;
link.target = newWindow ? '_blank' : this.externalLinkTarget || '';
Expand Down Expand Up @@ -149,4 +171,8 @@ export default class LinkService {
isPageCached() {
return true;
}

executeSetOCGState() {
// Intentionally empty
}
}
7 changes: 6 additions & 1 deletion src/Message.jsx → src/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';

export default function Message({ children, type }) {
type MessageProps = {
children: React.ReactNode;
type: 'error' | 'loading' | 'no-data';
};

export default function Message({ children, type }: MessageProps) {
return <div className={`react-pdf__message react-pdf__message--${type}`}>{children}</div>;
}

Expand Down
Loading

0 comments on commit e93a356

Please sign in to comment.