@nypl/web-reader 0.1.4 → 0.2.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ServiceWorker/sw.js +2 -0
- package/dist/cjs/ServiceWorker/sw.js.map +7 -0
- package/dist/cjs/index.js +683 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/esm/ServiceWorker/sw.js +1263 -0
- package/dist/esm/ServiceWorker/sw.js.map +7 -0
- package/dist/esm/index.js +88803 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/html-styles.css +2 -0
- package/dist/html-styles.css.map +7 -0
- package/dist/pdf-styles.css +2 -0
- package/dist/pdf-styles.css.map +7 -0
- package/dist/{HtmlReader → types/HtmlReader}/HtmlReaderContent.d.ts +3 -3
- package/dist/{HtmlReader → types/HtmlReader}/index.d.ts +22 -22
- package/dist/{HtmlReader → types/HtmlReader}/injectables.d.ts +30 -30
- package/dist/{PdfReader → types/PdfReader}/index.d.ts +11 -12
- package/dist/{PdfReader → types/PdfReader}/useMeasure.d.ts +7 -4
- package/dist/{ServiceWorker → types/ServiceWorker}/client.d.ts +9 -9
- package/dist/{ServiceWorker → types/ServiceWorker}/constants.d.ts +3 -3
- package/{src/ServiceWorker/index.ts → dist/types/ServiceWorker/index.d.ts} +0 -0
- package/dist/{ServiceWorker → types/ServiceWorker}/sw.d.ts +7 -7
- package/dist/{ServiceWorker → types/ServiceWorker}/types.d.ts +3 -3
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/ConformsTo.d.ts +3 -3
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/Contributor.d.ts +17 -17
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/EpubExtension.d.ts +47 -47
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/LanguageMap.d.ts +3 -3
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/Metadata.d.ts +46 -46
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/OPDSLink.d.ts +63 -63
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/PresentationHints.d.ts +53 -53
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/ReadiumLink.d.ts +58 -58
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/Subject.d.ts +16 -16
- package/dist/{WebpubManifestTypes → types/WebpubManifestTypes}/WebpubManifest.d.ts +14 -14
- package/dist/{constants.d.ts → types/constants.d.ts} +2 -2
- package/dist/{index.d.ts → types/index.d.ts} +7 -7
- package/dist/{types.d.ts → types/types.d.ts} +66 -66
- package/dist/{ui → types/ui}/Button.d.ts +9 -7
- package/dist/{ui → types/ui}/Header.d.ts +6 -6
- package/dist/{ui → types/ui}/HtmlSettings.d.ts +9 -9
- package/dist/{ui → types/ui}/PageButton.d.ts +7 -7
- package/dist/{ui → types/ui}/PdfSettings.d.ts +9 -9
- package/dist/{ui → types/ui}/SettingsButton.d.ts +5 -5
- package/dist/{ui → types/ui}/TableOfContent.d.ts +7 -7
- package/dist/{ui → types/ui}/ToggleButton.d.ts +10 -10
- package/dist/{ui → types/ui}/ToggleGroup.d.ts +8 -8
- package/dist/{ui → types/ui}/constants.d.ts +1 -1
- package/dist/{ui → types/ui}/hooks/useColorModeValue.d.ts +7 -7
- package/dist/{ui → types/ui}/hooks/useContainerWidth.d.ts +6 -6
- package/dist/{ui → types/ui}/hooks/useEventListener.d.ts +8 -8
- package/dist/{ui → types/ui}/manager.d.ts +9 -9
- package/dist/{ui → types/ui}/nypl-base-theme/components/button.d.ts +94 -94
- package/dist/{ui → types/ui}/nypl-base-theme/components/checkbox.d.ts +41 -41
- package/dist/{ui → types/ui}/nypl-base-theme/components/form-error.d.ts +14 -14
- package/dist/{ui → types/ui}/nypl-base-theme/components/form-label.d.ts +14 -14
- package/dist/{ui → types/ui}/nypl-base-theme/components/form.d.ts +15 -15
- package/dist/{ui → types/ui}/nypl-base-theme/components/input.d.ts +107 -107
- package/dist/{ui → types/ui}/nypl-base-theme/components/text-area.d.ts +34 -34
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/breakpoints.d.ts +8 -8
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/colors.d.ts +3 -3
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/global.d.ts +13 -13
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/radii.d.ts +12 -12
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/spacing.d.ts +49 -49
- package/dist/{ui → types/ui}/nypl-base-theme/foundations/typography.d.ts +10 -10
- package/dist/{ui → types/ui}/nypl-base-theme/index.d.ts +6 -6
- package/dist/{ui → types/ui}/nypl-base-theme/types.d.ts +1 -1
- package/dist/{ui → types/ui}/theme/components/button.d.ts +78 -78
- package/dist/{ui → types/ui}/theme/components/text.d.ts +20 -20
- package/dist/{ui → types/ui}/theme/foundations/colors.d.ts +3 -3
- package/dist/{ui → types/ui}/theme/index.d.ts +11 -11
- package/dist/{ui → types/ui}/theme/types.d.ts +1 -1
- package/dist/{useWebReader.d.ts → types/useWebReader.d.ts} +7 -7
- package/dist/{utils → types/utils}/decryptAxisNow.d.ts +0 -0
- package/dist/{utils → types/utils}/fetch.d.ts +4 -4
- package/dist/{utils → types/utils}/getColor.d.ts +2 -2
- package/dist/{utils → types/utils}/toggleFullScreen.d.ts +5 -5
- package/package.json +21 -33
- package/dist/ServiceWorker/index.d.ts +0 -1
- package/dist/index.js +0 -8
- package/dist/web-reader.cjs.development.js +0 -3363
- package/dist/web-reader.cjs.development.js.map +0 -1
- package/dist/web-reader.cjs.production.min.js +0 -2
- package/dist/web-reader.cjs.production.min.js.map +0 -1
- package/dist/web-reader.esm.js +0 -3356
- package/dist/web-reader.esm.js.map +0 -1
- package/src/HtmlReader/HtmlReaderContent.tsx +0 -19
- package/src/HtmlReader/index.tsx +0 -262
- package/src/HtmlReader/injectables.ts +0 -26
- package/src/PdfReader/index.tsx +0 -492
- package/src/PdfReader/useMeasure.tsx +0 -68
- package/src/ServiceWorker/client.ts +0 -106
- package/src/ServiceWorker/constants.ts +0 -4
- package/src/ServiceWorker/sw.ts +0 -84
- package/src/ServiceWorker/types.ts +0 -3
- package/src/WebpubManifestTypes/ConformsTo.ts +0 -9
- package/src/WebpubManifestTypes/Contributor.ts +0 -24
- package/src/WebpubManifestTypes/EpubExtension.ts +0 -48
- package/src/WebpubManifestTypes/LanguageMap.ts +0 -5
- package/src/WebpubManifestTypes/Metadata.ts +0 -48
- package/src/WebpubManifestTypes/OPDSLink.ts +0 -251
- package/src/WebpubManifestTypes/PresentationHints.ts +0 -54
- package/src/WebpubManifestTypes/ReadiumLink.ts +0 -61
- package/src/WebpubManifestTypes/Subject.ts +0 -20
- package/src/WebpubManifestTypes/WebpubManifest.ts +0 -15
- package/src/constants.ts +0 -3
- package/src/index.tsx +0 -25
- package/src/types.ts +0 -94
- package/src/ui/Button.tsx +0 -12
- package/src/ui/Header.tsx +0 -89
- package/src/ui/HtmlSettings.tsx +0 -97
- package/src/ui/PageButton.tsx +0 -39
- package/src/ui/PdfSettings.tsx +0 -85
- package/src/ui/SettingsButton.tsx +0 -71
- package/src/ui/TableOfContent.tsx +0 -144
- package/src/ui/ToggleButton.tsx +0 -60
- package/src/ui/ToggleGroup.tsx +0 -41
- package/src/ui/constants.ts +0 -2
- package/src/ui/hooks/useColorModeValue.tsx +0 -19
- package/src/ui/hooks/useContainerWidth.ts +0 -24
- package/src/ui/hooks/useEventListener.ts +0 -26
- package/src/ui/manager.tsx +0 -73
- package/src/ui/nypl-base-theme/components/button.ts +0 -117
- package/src/ui/nypl-base-theme/components/checkbox.ts +0 -45
- package/src/ui/nypl-base-theme/components/form-error.ts +0 -15
- package/src/ui/nypl-base-theme/components/form-label.ts +0 -15
- package/src/ui/nypl-base-theme/components/form.ts +0 -16
- package/src/ui/nypl-base-theme/components/input.ts +0 -101
- package/src/ui/nypl-base-theme/components/text-area.ts +0 -17
- package/src/ui/nypl-base-theme/foundations/breakpoints.ts +0 -10
- package/src/ui/nypl-base-theme/foundations/colors.ts +0 -136
- package/src/ui/nypl-base-theme/foundations/global.ts +0 -16
- package/src/ui/nypl-base-theme/foundations/radii.ts +0 -13
- package/src/ui/nypl-base-theme/foundations/spacing.ts +0 -58
- package/src/ui/nypl-base-theme/foundations/typography.ts +0 -43
- package/src/ui/nypl-base-theme/index.ts +0 -42
- package/src/ui/nypl-base-theme/types.ts +0 -1
- package/src/ui/theme/components/button.ts +0 -85
- package/src/ui/theme/components/text.ts +0 -24
- package/src/ui/theme/foundations/colors.ts +0 -10
- package/src/ui/theme/index.ts +0 -34
- package/src/ui/theme/types.ts +0 -1
- package/src/useWebReader.tsx +0 -105
- package/src/utils/decryptAxisNow.ts +0 -45
- package/src/utils/fetch.ts +0 -13
- package/src/utils/getColor.ts +0 -14
- package/src/utils/toggleFullScreen.ts +0 -71
package/src/PdfReader/index.tsx
DELETED
|
@@ -1,492 +0,0 @@
|
|
|
1
|
-
import { Document, Page, PageProps, pdfjs } from 'react-pdf';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import {
|
|
4
|
-
ColorMode,
|
|
5
|
-
ReaderArguments,
|
|
6
|
-
ReaderReturn,
|
|
7
|
-
WebpubManifest,
|
|
8
|
-
PdfReaderState,
|
|
9
|
-
} from '../types';
|
|
10
|
-
import { chakra, Flex, shouldForwardProp } from '@chakra-ui/react';
|
|
11
|
-
import useMeasure from './useMeasure';
|
|
12
|
-
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
|
13
|
-
import { ReadiumLink } from '../WebpubManifestTypes/ReadiumLink';
|
|
14
|
-
|
|
15
|
-
type PdfState = PdfReaderState & {
|
|
16
|
-
resourceIndex: number;
|
|
17
|
-
resource: { data: Uint8Array } | null;
|
|
18
|
-
// we only know the numPages once the resource has been parsed
|
|
19
|
-
numPages: number | null;
|
|
20
|
-
// if pageNumber is -1, we will navigate to the end of the
|
|
21
|
-
// resource once it is parsed
|
|
22
|
-
pageNumber: number;
|
|
23
|
-
scale: number;
|
|
24
|
-
pdfHeight: number;
|
|
25
|
-
pdfWidth: number;
|
|
26
|
-
pageHeight: number | undefined;
|
|
27
|
-
pageWidth: number | undefined;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
pdfjs.GlobalWorkerOptions.workerSrc = `pdf.worker.min.js`;
|
|
31
|
-
|
|
32
|
-
type PdfReaderAction =
|
|
33
|
-
| {
|
|
34
|
-
type: 'SET_CURRENT_RESOURCE';
|
|
35
|
-
index: number;
|
|
36
|
-
shouldNavigateToEnd: boolean;
|
|
37
|
-
}
|
|
38
|
-
| { type: 'RESOURCE_FETCH_SUCCESS'; resource: { data: Uint8Array } }
|
|
39
|
-
| { type: 'PDF_PARSED'; numPages: number }
|
|
40
|
-
| { type: 'NAVIGATE_PAGE'; pageNum: number }
|
|
41
|
-
| { type: 'SET_COLOR_MODE'; mode: ColorMode }
|
|
42
|
-
| { type: 'SET_SCALE'; scale: number }
|
|
43
|
-
| { type: 'SET_SCROLL'; isScrolling: boolean }
|
|
44
|
-
| { type: 'PAGE_LOAD_SUCCESS'; height: number; width: number }
|
|
45
|
-
| {
|
|
46
|
-
type: 'RESIZE_PAGE';
|
|
47
|
-
height: number | undefined;
|
|
48
|
-
width: number | undefined;
|
|
49
|
-
};
|
|
50
|
-
const IFRAME_WRAPPER_ID = 'iframe-wrapper';
|
|
51
|
-
|
|
52
|
-
function pdfReducer(state: PdfState, action: PdfReaderAction): PdfState {
|
|
53
|
-
switch (action.type) {
|
|
54
|
-
/**
|
|
55
|
-
* Cleares the current resource and sets the current index, which will cause
|
|
56
|
-
* the useEffect hook to load a new resource.
|
|
57
|
-
*/
|
|
58
|
-
case 'SET_CURRENT_RESOURCE':
|
|
59
|
-
return {
|
|
60
|
-
...state,
|
|
61
|
-
resource: null,
|
|
62
|
-
resourceIndex: action.index,
|
|
63
|
-
pageNumber: action.shouldNavigateToEnd ? -1 : 1,
|
|
64
|
-
numPages: null,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
case 'RESOURCE_FETCH_SUCCESS':
|
|
68
|
-
return {
|
|
69
|
-
...state,
|
|
70
|
-
resource: action.resource,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// called when the resource has been parsed by react-pdf
|
|
74
|
-
// and we know the number of pages
|
|
75
|
-
case 'PDF_PARSED':
|
|
76
|
-
return {
|
|
77
|
-
...state,
|
|
78
|
-
numPages: action.numPages,
|
|
79
|
-
// if the state.pageNumber is -1, we know to navigate to the
|
|
80
|
-
// end of the PDF that was just parsed
|
|
81
|
-
pageNumber:
|
|
82
|
-
state.pageNumber === -1 ? action.numPages : state.pageNumber,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// Navigates to page in resource
|
|
86
|
-
case 'NAVIGATE_PAGE':
|
|
87
|
-
return {
|
|
88
|
-
...state,
|
|
89
|
-
pageNumber: action.pageNum,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
case 'SET_COLOR_MODE':
|
|
93
|
-
return {
|
|
94
|
-
...state,
|
|
95
|
-
colorMode: action.mode,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
case 'SET_SCROLL':
|
|
99
|
-
return {
|
|
100
|
-
...state,
|
|
101
|
-
isScrolling: action.isScrolling,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
case 'SET_SCALE':
|
|
105
|
-
return {
|
|
106
|
-
...state,
|
|
107
|
-
scale: action.scale,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
case 'PAGE_LOAD_SUCCESS':
|
|
111
|
-
return {
|
|
112
|
-
...state,
|
|
113
|
-
pdfWidth: action.width,
|
|
114
|
-
pdfHeight: action.height,
|
|
115
|
-
pageWidth: action.width,
|
|
116
|
-
pageHeight: action.height,
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
case 'RESIZE_PAGE':
|
|
120
|
-
return {
|
|
121
|
-
...state,
|
|
122
|
-
pageWidth: action.width,
|
|
123
|
-
pageHeight: action.height,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const getResourceUrl = (
|
|
129
|
-
index: number,
|
|
130
|
-
readingOrder: ReadiumLink[] | undefined
|
|
131
|
-
): string => {
|
|
132
|
-
if (!readingOrder || !readingOrder.length) {
|
|
133
|
-
throw new Error('A manifest has been returned, but has no reading order');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// If it has no children, return the link href
|
|
137
|
-
return readingOrder[index].href;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const loadResource = async (resourceUrl: string, proxyUrl?: string) => {
|
|
141
|
-
// Generate the resource URL using the proxy
|
|
142
|
-
const resource: string = proxyUrl + encodeURI(resourceUrl);
|
|
143
|
-
const response = await fetch(resource, { mode: 'cors' });
|
|
144
|
-
const array = new Uint8Array(await response.arrayBuffer());
|
|
145
|
-
|
|
146
|
-
if (!response.ok) {
|
|
147
|
-
throw new Error('Response not Ok for URL: ' + resource);
|
|
148
|
-
}
|
|
149
|
-
return array;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* The PDF reader
|
|
154
|
-
*
|
|
155
|
-
* The PDF reader loads resources in two stages: First, it fetches the PDF resource as an Uint8Array
|
|
156
|
-
* Then, it passes this array into the <Document> object, which loads the PDF inside an iframe
|
|
157
|
-
*
|
|
158
|
-
* @param args T
|
|
159
|
-
* @returns
|
|
160
|
-
*/
|
|
161
|
-
export default function usePdfReader(args: ReaderArguments): ReaderReturn {
|
|
162
|
-
const { webpubManifestUrl, manifest, proxyUrl } = args ?? {};
|
|
163
|
-
const [state, dispatch] = React.useReducer(pdfReducer, {
|
|
164
|
-
colorMode: 'day',
|
|
165
|
-
isScrolling: false,
|
|
166
|
-
fontSize: 16,
|
|
167
|
-
fontFamily: 'sans-serif',
|
|
168
|
-
resourceIndex: 0,
|
|
169
|
-
resource: null,
|
|
170
|
-
pageNumber: 1,
|
|
171
|
-
numPages: null,
|
|
172
|
-
currentTocUrl: null,
|
|
173
|
-
scale: 1,
|
|
174
|
-
pdfWidth: 0,
|
|
175
|
-
pdfHeight: 0,
|
|
176
|
-
pageHeight: undefined,
|
|
177
|
-
pageWidth: undefined,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// state we can derive from the state above
|
|
181
|
-
const isFetching = !state.resource;
|
|
182
|
-
const isParsed = typeof state.numPages === 'number';
|
|
183
|
-
const [containerRef, containerSize] = useMeasure<HTMLDivElement>();
|
|
184
|
-
|
|
185
|
-
// Wrap Page component so that we can pass it styles
|
|
186
|
-
const ChakraPage = chakra(Page, {
|
|
187
|
-
shouldForwardProp: (prop) => {
|
|
188
|
-
// Definitely forward width and height
|
|
189
|
-
if (['width', 'height', 'scale'].includes(prop)) return true;
|
|
190
|
-
// don't forward the rest of Chakra's props
|
|
191
|
-
const isChakraProp = !shouldForwardProp(prop);
|
|
192
|
-
if (isChakraProp) return false;
|
|
193
|
-
// else, only forward `sample` prop
|
|
194
|
-
return true;
|
|
195
|
-
},
|
|
196
|
-
baseStyle: {
|
|
197
|
-
outline: '1px',
|
|
198
|
-
outlineColor: 'ui.gray.light-cool',
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Load the current resource and set it in state,
|
|
204
|
-
* and reload whenever it changes (via navigation)
|
|
205
|
-
*/
|
|
206
|
-
React.useEffect(() => {
|
|
207
|
-
// bail out if there is not manifest passed in,
|
|
208
|
-
// that indicates that this format is inactive
|
|
209
|
-
if (!manifest) return;
|
|
210
|
-
// throw an error on a badly formed manifest
|
|
211
|
-
if (!manifest.readingOrder || !manifest.readingOrder.length) {
|
|
212
|
-
throw new Error('Manifest has no Reading Order');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const resourceUrl = getResourceUrl(
|
|
216
|
-
state.resourceIndex,
|
|
217
|
-
manifest.readingOrder
|
|
218
|
-
);
|
|
219
|
-
loadResource(resourceUrl, proxyUrl).then((data) => {
|
|
220
|
-
dispatch({
|
|
221
|
-
type: 'RESOURCE_FETCH_SUCCESS',
|
|
222
|
-
resource: { data },
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
}, [state.resourceIndex, manifest, proxyUrl]);
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* calculate the height or width of the pdf page in paginated mode.
|
|
229
|
-
* - if the page's aspect ratio is taller than the container's, we will constrain
|
|
230
|
-
* the page to the height of the container.
|
|
231
|
-
* - if the page's aspect ratio is wider than the container's, we will constrain
|
|
232
|
-
* the page to the width of the container
|
|
233
|
-
*/
|
|
234
|
-
|
|
235
|
-
const resizePage = React.useCallback(
|
|
236
|
-
(
|
|
237
|
-
pdfWidth: number,
|
|
238
|
-
pdfHeight: number,
|
|
239
|
-
containerSize: { width: number; height: number }
|
|
240
|
-
) => {
|
|
241
|
-
const wRatio = pdfWidth / containerSize.width;
|
|
242
|
-
const hRatio = pdfHeight / containerSize.height;
|
|
243
|
-
|
|
244
|
-
const fitHorizontal = wRatio > hRatio;
|
|
245
|
-
const width = fitHorizontal ? Math.round(containerSize.width) : undefined;
|
|
246
|
-
const height = !fitHorizontal
|
|
247
|
-
? Math.round(containerSize.height)
|
|
248
|
-
: undefined;
|
|
249
|
-
|
|
250
|
-
dispatch({ type: 'RESIZE_PAGE', width, height });
|
|
251
|
-
},
|
|
252
|
-
[]
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
//TODO: Somehow, this window size updates when height
|
|
256
|
-
React.useEffect(() => {
|
|
257
|
-
if (containerSize) {
|
|
258
|
-
resizePage(state.pdfWidth, state.pdfHeight, containerSize);
|
|
259
|
-
}
|
|
260
|
-
}, [containerSize, state.pdfWidth, state.pdfHeight, resizePage]);
|
|
261
|
-
|
|
262
|
-
// prev and next page functions
|
|
263
|
-
const goForward = React.useCallback(async () => {
|
|
264
|
-
// do nothing if we haven't parsed the number of pages yet
|
|
265
|
-
if (!state.numPages) return;
|
|
266
|
-
|
|
267
|
-
if (state.pageNumber < state.numPages && !state.isScrolling) {
|
|
268
|
-
dispatch({
|
|
269
|
-
type: 'NAVIGATE_PAGE',
|
|
270
|
-
pageNum: state.pageNumber + 1,
|
|
271
|
-
});
|
|
272
|
-
} else if (
|
|
273
|
-
manifest &&
|
|
274
|
-
manifest.readingOrder &&
|
|
275
|
-
state.resourceIndex < manifest?.readingOrder?.length - 1
|
|
276
|
-
) {
|
|
277
|
-
const nextIndex = state.resourceIndex + 1;
|
|
278
|
-
dispatch({
|
|
279
|
-
type: 'SET_CURRENT_RESOURCE',
|
|
280
|
-
index: nextIndex,
|
|
281
|
-
shouldNavigateToEnd: false,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
// Do nothing if it's at the last page of the last resource
|
|
285
|
-
}, [
|
|
286
|
-
manifest,
|
|
287
|
-
state.isScrolling,
|
|
288
|
-
state.numPages,
|
|
289
|
-
state.pageNumber,
|
|
290
|
-
state.resourceIndex,
|
|
291
|
-
]);
|
|
292
|
-
|
|
293
|
-
const goBackward = React.useCallback(async () => {
|
|
294
|
-
// do nothing if we haven't parsed the PDF yet
|
|
295
|
-
if (!isParsed) return;
|
|
296
|
-
|
|
297
|
-
if (state.pageNumber > 1) {
|
|
298
|
-
dispatch({
|
|
299
|
-
type: 'NAVIGATE_PAGE',
|
|
300
|
-
pageNum: state.pageNumber - 1,
|
|
301
|
-
});
|
|
302
|
-
} else if (manifest?.readingOrder && state.resourceIndex > 0) {
|
|
303
|
-
const nextIndex = state.resourceIndex - 1;
|
|
304
|
-
dispatch({
|
|
305
|
-
type: 'SET_CURRENT_RESOURCE',
|
|
306
|
-
index: nextIndex,
|
|
307
|
-
shouldNavigateToEnd: !state.isScrolling,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}, [
|
|
311
|
-
manifest,
|
|
312
|
-
isParsed,
|
|
313
|
-
state.isScrolling,
|
|
314
|
-
state.pageNumber,
|
|
315
|
-
state.resourceIndex,
|
|
316
|
-
]);
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* These ones don't make sense in the PDF case I dont think. I'm still
|
|
320
|
-
* deciding how we will separate the types of Navigators and States, so
|
|
321
|
-
* for now just pass dummies through.
|
|
322
|
-
*/
|
|
323
|
-
const setColorMode = React.useCallback(async () => {
|
|
324
|
-
console.log('unimplemented');
|
|
325
|
-
}, []);
|
|
326
|
-
|
|
327
|
-
const setScroll = React.useCallback(
|
|
328
|
-
async (val: 'scrolling' | 'paginated') => {
|
|
329
|
-
const isScrolling = val === 'scrolling';
|
|
330
|
-
dispatch({ type: 'SET_SCROLL', isScrolling });
|
|
331
|
-
},
|
|
332
|
-
[]
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* TODO: Change this button into a different "scale" button
|
|
337
|
-
*/
|
|
338
|
-
const increaseFontSize = React.useCallback(async () => {
|
|
339
|
-
dispatch({
|
|
340
|
-
type: 'SET_SCALE',
|
|
341
|
-
scale: state.scale + 0.1,
|
|
342
|
-
});
|
|
343
|
-
}, [state.scale]);
|
|
344
|
-
|
|
345
|
-
const decreaseFontSize = React.useCallback(async () => {
|
|
346
|
-
dispatch({
|
|
347
|
-
type: 'SET_SCALE',
|
|
348
|
-
scale: state.scale - 0.1,
|
|
349
|
-
});
|
|
350
|
-
}, [state.scale]);
|
|
351
|
-
|
|
352
|
-
const setFontFamily = React.useCallback(async () => {
|
|
353
|
-
console.log('unimplemented');
|
|
354
|
-
}, []);
|
|
355
|
-
|
|
356
|
-
const goToPage = React.useCallback(
|
|
357
|
-
async (href) => {
|
|
358
|
-
const getIndexFromHref = (href: string): number => {
|
|
359
|
-
const index = manifest?.readingOrder?.findIndex((link) => {
|
|
360
|
-
return link.href === href;
|
|
361
|
-
});
|
|
362
|
-
if (!index) {
|
|
363
|
-
throw new Error('Cannot find resource in readingOrder');
|
|
364
|
-
}
|
|
365
|
-
return index;
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
dispatch({
|
|
369
|
-
type: 'SET_CURRENT_RESOURCE',
|
|
370
|
-
index: getIndexFromHref(href),
|
|
371
|
-
shouldNavigateToEnd: false,
|
|
372
|
-
});
|
|
373
|
-
},
|
|
374
|
-
[manifest?.readingOrder]
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
// this format is inactive, return null
|
|
378
|
-
if (!webpubManifestUrl || !manifest) return null;
|
|
379
|
-
|
|
380
|
-
if (isFetching) {
|
|
381
|
-
// The Reader is fetching a PDF resource
|
|
382
|
-
return {
|
|
383
|
-
type: 'PDF',
|
|
384
|
-
isLoading: false,
|
|
385
|
-
content: (
|
|
386
|
-
<Flex
|
|
387
|
-
as="main"
|
|
388
|
-
tabIndex={-1}
|
|
389
|
-
id="iframe-wrapper"
|
|
390
|
-
zIndex="base"
|
|
391
|
-
alignItems="center"
|
|
392
|
-
justifyContent="center"
|
|
393
|
-
flex="1 0 auto"
|
|
394
|
-
>
|
|
395
|
-
PDF is loading
|
|
396
|
-
</Flex>
|
|
397
|
-
),
|
|
398
|
-
state,
|
|
399
|
-
manifest,
|
|
400
|
-
navigator: {
|
|
401
|
-
goForward,
|
|
402
|
-
goBackward,
|
|
403
|
-
increaseFontSize,
|
|
404
|
-
decreaseFontSize,
|
|
405
|
-
setFontFamily,
|
|
406
|
-
setColorMode,
|
|
407
|
-
setScroll,
|
|
408
|
-
goToPage,
|
|
409
|
-
},
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function onDocumentLoadSuccess({ numPages }: { numPages: number }) {
|
|
414
|
-
dispatch({
|
|
415
|
-
type: 'PDF_PARSED',
|
|
416
|
-
numPages: numPages,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function onRenderSuccess(page: PageProps) {
|
|
421
|
-
if (!page.height || !page.width || !containerSize)
|
|
422
|
-
throw new Error('Error rendering page from Reader');
|
|
423
|
-
if (
|
|
424
|
-
Math.round(page.height) !== state.pdfHeight ||
|
|
425
|
-
Math.round(page.width) !== state.pdfWidth
|
|
426
|
-
) {
|
|
427
|
-
dispatch({
|
|
428
|
-
type: 'PAGE_LOAD_SUCCESS',
|
|
429
|
-
height: Math.round(page.height),
|
|
430
|
-
width: Math.round(page.width),
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
resizePage(page.width, page.height, containerSize);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// the reader is active but loading a page
|
|
438
|
-
return {
|
|
439
|
-
type: 'PDF',
|
|
440
|
-
isLoading: false,
|
|
441
|
-
content: (
|
|
442
|
-
<Flex
|
|
443
|
-
as="main"
|
|
444
|
-
zIndex="base"
|
|
445
|
-
flex="1 0 auto"
|
|
446
|
-
justifyContent="center"
|
|
447
|
-
alignItems="center"
|
|
448
|
-
tabIndex={-1}
|
|
449
|
-
id={IFRAME_WRAPPER_ID}
|
|
450
|
-
ref={containerRef}
|
|
451
|
-
>
|
|
452
|
-
<Document file={state.resource} onLoadSuccess={onDocumentLoadSuccess}>
|
|
453
|
-
{isParsed && state.numPages && (
|
|
454
|
-
<>
|
|
455
|
-
{state.isScrolling &&
|
|
456
|
-
Array.from(new Array(state.numPages), (_, index) => (
|
|
457
|
-
<ChakraPage
|
|
458
|
-
key={`page_${index + 1}`}
|
|
459
|
-
width={containerSize?.width}
|
|
460
|
-
scale={state.scale}
|
|
461
|
-
pageNumber={index + 1}
|
|
462
|
-
/>
|
|
463
|
-
))}
|
|
464
|
-
{!state.isScrolling && (
|
|
465
|
-
<ChakraPage
|
|
466
|
-
pageNumber={state.pageNumber}
|
|
467
|
-
onLoadSuccess={onRenderSuccess}
|
|
468
|
-
width={state.pageWidth}
|
|
469
|
-
height={state.pageHeight}
|
|
470
|
-
scale={state.scale}
|
|
471
|
-
loading={<></>}
|
|
472
|
-
/>
|
|
473
|
-
)}
|
|
474
|
-
</>
|
|
475
|
-
)}
|
|
476
|
-
</Document>
|
|
477
|
-
</Flex>
|
|
478
|
-
),
|
|
479
|
-
state,
|
|
480
|
-
manifest,
|
|
481
|
-
navigator: {
|
|
482
|
-
goForward,
|
|
483
|
-
goBackward,
|
|
484
|
-
setColorMode,
|
|
485
|
-
setScroll,
|
|
486
|
-
increaseFontSize,
|
|
487
|
-
decreaseFontSize,
|
|
488
|
-
setFontFamily,
|
|
489
|
-
goToPage,
|
|
490
|
-
},
|
|
491
|
-
};
|
|
492
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
declare const window: Window &
|
|
4
|
-
typeof globalThis & {
|
|
5
|
-
ResizeObserver: any;
|
|
6
|
-
};
|
|
7
|
-
export type Dimensions = Pick<
|
|
8
|
-
DOMRectReadOnly,
|
|
9
|
-
'x' | 'y' | 'top' | 'left' | 'right' | 'bottom' | 'height' | 'width'
|
|
10
|
-
>;
|
|
11
|
-
export type UseMeasureRef<E extends Element = Element> = (element: E) => void;
|
|
12
|
-
export type UseMeasureResult<E extends Element = Element> = [
|
|
13
|
-
UseMeasureRef<E> | null,
|
|
14
|
-
Dimensions | null
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
export default function useMeasure<
|
|
18
|
-
E extends Element = Element
|
|
19
|
-
>(): UseMeasureResult<E> {
|
|
20
|
-
// this is a little trick to get a reference to an HTML element. Using useRef wouldn't
|
|
21
|
-
// work because we actually need rerenders when it changes, to update the useLayoutEffect
|
|
22
|
-
const [element, ref] = React.useState<E | null>(null);
|
|
23
|
-
const [rect, setRect] = React.useState<Dimensions | null>(null);
|
|
24
|
-
const observer = React.useMemo(
|
|
25
|
-
() =>
|
|
26
|
-
new window.ResizeObserver(
|
|
27
|
-
(
|
|
28
|
-
entries: {
|
|
29
|
-
contentRect: {
|
|
30
|
-
x: any;
|
|
31
|
-
y: any;
|
|
32
|
-
width: any;
|
|
33
|
-
height: any;
|
|
34
|
-
top: any;
|
|
35
|
-
left: any;
|
|
36
|
-
bottom: any;
|
|
37
|
-
right: any;
|
|
38
|
-
};
|
|
39
|
-
}[]
|
|
40
|
-
) => {
|
|
41
|
-
if (entries[0]) {
|
|
42
|
-
const {
|
|
43
|
-
x,
|
|
44
|
-
y,
|
|
45
|
-
width,
|
|
46
|
-
height,
|
|
47
|
-
top,
|
|
48
|
-
left,
|
|
49
|
-
bottom,
|
|
50
|
-
right,
|
|
51
|
-
} = entries[0].contentRect;
|
|
52
|
-
setRect({ x, y, width, height, top, left, bottom, right });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
),
|
|
56
|
-
[]
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
React.useLayoutEffect(() => {
|
|
60
|
-
if (!element) return;
|
|
61
|
-
observer.observe(element);
|
|
62
|
-
return () => {
|
|
63
|
-
observer.disconnect();
|
|
64
|
-
};
|
|
65
|
-
}, [element, observer]);
|
|
66
|
-
|
|
67
|
-
return [ref, rect];
|
|
68
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { WebpubManifest } from '../WebpubManifestTypes/WebpubManifest';
|
|
3
|
-
import { ReadiumLink } from '../WebpubManifestTypes/ReadiumLink';
|
|
4
|
-
import { WEBPUB_CACHE_NAME } from './constants';
|
|
5
|
-
|
|
6
|
-
export type PublicationConfig = {
|
|
7
|
-
manifestUrl: string;
|
|
8
|
-
proxyUrl?: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Will add all publication resources to the cache so they
|
|
13
|
-
* can be picked up by the SW.
|
|
14
|
-
*/
|
|
15
|
-
export default function usePublicationSW(
|
|
16
|
-
publications: PublicationConfig[]
|
|
17
|
-
): void {
|
|
18
|
-
// add each manifest and its resources to the cache directly
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
async function cachePublications() {
|
|
21
|
-
const cache = await caches.open(WEBPUB_CACHE_NAME);
|
|
22
|
-
|
|
23
|
-
const promises = publications.map(async (pub) => {
|
|
24
|
-
const finalManifestUrl = getProxiedUrl(pub.manifestUrl, pub.proxyUrl);
|
|
25
|
-
const manifestResponse = await fetch(finalManifestUrl);
|
|
26
|
-
handleBadResponse(finalManifestUrl, manifestResponse);
|
|
27
|
-
// add the manifest response to the cache
|
|
28
|
-
await cache.put(finalManifestUrl, manifestResponse.clone());
|
|
29
|
-
|
|
30
|
-
const manifest: WebpubManifest = await manifestResponse.json();
|
|
31
|
-
|
|
32
|
-
// make a list of resources with proxy included
|
|
33
|
-
const resourceHrefs = extractHrefs(
|
|
34
|
-
manifest.resources ?? [],
|
|
35
|
-
pub.manifestUrl,
|
|
36
|
-
pub.proxyUrl
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const readingOrderHrefs = extractHrefs(
|
|
40
|
-
manifest.readingOrder ?? [],
|
|
41
|
-
pub.manifestUrl,
|
|
42
|
-
pub.proxyUrl
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
// make sure array is deduped using set or we may get a cache error
|
|
46
|
-
const allResourcesToCache = Array.from(
|
|
47
|
-
new Set([...resourceHrefs, ...readingOrderHrefs])
|
|
48
|
-
);
|
|
49
|
-
// add them all to the cache
|
|
50
|
-
await Promise.all(
|
|
51
|
-
allResourcesToCache.map(async (url) => {
|
|
52
|
-
const response = await fetch(url);
|
|
53
|
-
handleBadResponse(url, response);
|
|
54
|
-
return await cache.put(url, response);
|
|
55
|
-
})
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
// wait for this to finish for all of the manifests, but don't reject if one fails
|
|
59
|
-
return await Promise.allSettled(promises);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
cachePublications();
|
|
63
|
-
}, [publications]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function handleBadResponse(url: string, response: Response) {
|
|
67
|
-
if (!response.ok) {
|
|
68
|
-
const message = `Bad response status for: ${url}. Status: ${response.status}`;
|
|
69
|
-
console.warn(message);
|
|
70
|
-
throw new Error(message);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Prepends the proxy url if there is one
|
|
76
|
-
*/
|
|
77
|
-
function getProxiedUrl(url: string, proxyUrl: string | undefined) {
|
|
78
|
-
return proxyUrl ? `${proxyUrl}${encodeURIComponent(url)}` : url;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* If the passed in url is relative, it will resolve it relative to the
|
|
83
|
-
* manifest url. Otherwise it should stay the same. Finally, the proxy is
|
|
84
|
-
* conditionally added
|
|
85
|
-
*/
|
|
86
|
-
function getAbsoluteUrl(
|
|
87
|
-
maybeRelative: string,
|
|
88
|
-
manifestUrl: string,
|
|
89
|
-
proxyUrl?: string
|
|
90
|
-
) {
|
|
91
|
-
return getProxiedUrl(
|
|
92
|
-
new URL(maybeRelative, manifestUrl).toString(),
|
|
93
|
-
proxyUrl
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Gets an array of raw href values from an array of readium links
|
|
99
|
-
*/
|
|
100
|
-
function extractHrefs(
|
|
101
|
-
links: ReadiumLink[],
|
|
102
|
-
manifestUrl: string,
|
|
103
|
-
proxyUrl: string | undefined
|
|
104
|
-
): string[] {
|
|
105
|
-
return links.map((res) => getAbsoluteUrl(res.href, manifestUrl, proxyUrl));
|
|
106
|
-
}
|