@blocklet/pdf 1.6.61
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/LICENSE +13 -0
- package/README.md +65 -0
- package/lib/index.cjs +333 -0
- package/lib/index.d.cts +13 -0
- package/lib/index.d.mts +13 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +333 -0
- package/lib/index.mjs +318 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2018-2020 ArcBlock
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @blocklet/pdf
|
|
2
|
+
|
|
3
|
+
**@blocklet/pdf** is a package that integrates the **react/pdf** service to provide universal pdf capability for blocklets. For more information about react/pdf, refer to the [official documentation](https://www.npmjs.com/package/react-pdf).
|
|
4
|
+
|
|
5
|
+
## Package Structure
|
|
6
|
+
|
|
7
|
+
The package is composed of both frontend and backend components. The frontend code resides in the `index.js` file
|
|
8
|
+
|
|
9
|
+
## Development
|
|
10
|
+
|
|
11
|
+
### Install In Blocklet
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
# You can use npm / yarn
|
|
15
|
+
pnpm add @blocklet/pdf
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Install Dependencies
|
|
19
|
+
|
|
20
|
+
To install the required dependencies, run the following command:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
pnpm i
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Build Packages
|
|
27
|
+
|
|
28
|
+
To build the packages, execute the following command:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
pnpm build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Build, Watch, and Run Development Server
|
|
35
|
+
|
|
36
|
+
For building, watching changes, and running the development server, use the following command:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
pnpm run dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Frontend Example
|
|
43
|
+
|
|
44
|
+
```jsx
|
|
45
|
+
import { lazy } from 'react';
|
|
46
|
+
|
|
47
|
+
const PdfComponent = React.lazy(() =>
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
import('@blocklet/pdf').then((module) => {
|
|
50
|
+
return {
|
|
51
|
+
default: module.PdfComponent,
|
|
52
|
+
};
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
<Box>
|
|
59
|
+
<PdfComponent url={pdfUrl} maxHeight="60vh" />
|
|
60
|
+
</Box>;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
This package is licensed under the MIT license.
|
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
const react = require('react');
|
|
5
|
+
const reactPdf = require('react-pdf');
|
|
6
|
+
const ahooks = require('ahooks');
|
|
7
|
+
const useTheme = require('@mui/material/styles/useTheme');
|
|
8
|
+
const useMediaQuery = require('@mui/material/useMediaQuery');
|
|
9
|
+
const Box = require('@mui/material/Box');
|
|
10
|
+
const Skeleton = require('@mui/material/Skeleton');
|
|
11
|
+
const IconButton = require('@mui/material/IconButton');
|
|
12
|
+
const FullscreenIcon = require('@mui/icons-material/Fullscreen');
|
|
13
|
+
const ZoomOutIcon = require('@mui/icons-material/ZoomOut');
|
|
14
|
+
const ZoomInIcon = require('@mui/icons-material/ZoomIn');
|
|
15
|
+
const DownloadIcon = require('@mui/icons-material/Download');
|
|
16
|
+
const ArrowOutwardOutlinedIcon = require('@mui/icons-material/ArrowOutwardOutlined');
|
|
17
|
+
const material = require('@mui/material');
|
|
18
|
+
require('react-pdf/dist/Page/AnnotationLayer.css');
|
|
19
|
+
require('react-pdf/dist/Page/TextLayer.css');
|
|
20
|
+
|
|
21
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
22
|
+
|
|
23
|
+
const useTheme__default = /*#__PURE__*/_interopDefaultCompat(useTheme);
|
|
24
|
+
const useMediaQuery__default = /*#__PURE__*/_interopDefaultCompat(useMediaQuery);
|
|
25
|
+
const Box__default = /*#__PURE__*/_interopDefaultCompat(Box);
|
|
26
|
+
const Skeleton__default = /*#__PURE__*/_interopDefaultCompat(Skeleton);
|
|
27
|
+
const IconButton__default = /*#__PURE__*/_interopDefaultCompat(IconButton);
|
|
28
|
+
const FullscreenIcon__default = /*#__PURE__*/_interopDefaultCompat(FullscreenIcon);
|
|
29
|
+
const ZoomOutIcon__default = /*#__PURE__*/_interopDefaultCompat(ZoomOutIcon);
|
|
30
|
+
const ZoomInIcon__default = /*#__PURE__*/_interopDefaultCompat(ZoomInIcon);
|
|
31
|
+
const DownloadIcon__default = /*#__PURE__*/_interopDefaultCompat(DownloadIcon);
|
|
32
|
+
const ArrowOutwardOutlinedIcon__default = /*#__PURE__*/_interopDefaultCompat(ArrowOutwardOutlinedIcon);
|
|
33
|
+
|
|
34
|
+
const workerSrc = `//unpkg.com/pdfjs-dist@${reactPdf.pdfjs.version}/legacy/build/pdf.worker.min.js`;
|
|
35
|
+
reactPdf.pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
36
|
+
const preventScrollChangeThumbnailTimerMap = {};
|
|
37
|
+
const getBorder = (color) => `2px solid ${color}`;
|
|
38
|
+
const defaultLoading = (props) => {
|
|
39
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Skeleton__default, { variant: "rectangular", width: "100%", ...props });
|
|
40
|
+
};
|
|
41
|
+
function PdfComponent({
|
|
42
|
+
url,
|
|
43
|
+
backgroundColor = "#fbfbfb",
|
|
44
|
+
loading = defaultLoading,
|
|
45
|
+
maxHeight = "60vh",
|
|
46
|
+
...rest
|
|
47
|
+
}) {
|
|
48
|
+
const pdfPageWrapperRef = react.useRef(null);
|
|
49
|
+
const thumbnailWrapperRef = react.useRef(null);
|
|
50
|
+
const preventScrollChangeThumbnailRef = react.useRef(false);
|
|
51
|
+
const state = ahooks.useReactive({
|
|
52
|
+
currentPage: 1,
|
|
53
|
+
totalPage: 1,
|
|
54
|
+
scale: 1
|
|
55
|
+
});
|
|
56
|
+
const wrapperSize = ahooks.useSize(pdfPageWrapperRef);
|
|
57
|
+
const theme = useTheme__default();
|
|
58
|
+
const isMobile = useMediaQuery__default(theme.breakpoints.down("sm"));
|
|
59
|
+
const pdfUrl = url;
|
|
60
|
+
const getPdfItemHeight = () => pdfPageWrapperRef.current?.children[0]?.offsetHeight;
|
|
61
|
+
const onDocumentLoadSuccess = (pdf) => {
|
|
62
|
+
state.totalPage = pdf.numPages;
|
|
63
|
+
};
|
|
64
|
+
const onPageChange = (page) => {
|
|
65
|
+
state.currentPage = page;
|
|
66
|
+
preventScrollChangeThumbnailRef.current = true;
|
|
67
|
+
const top = getPdfItemHeight() * (page - 1);
|
|
68
|
+
pdfPageWrapperRef?.current?.scrollTo({
|
|
69
|
+
top,
|
|
70
|
+
behavior: "smooth"
|
|
71
|
+
});
|
|
72
|
+
if (preventScrollChangeThumbnailTimerMap[pdfUrl])
|
|
73
|
+
clearTimeout(preventScrollChangeThumbnailTimerMap[pdfUrl]);
|
|
74
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = setTimeout(() => {
|
|
75
|
+
preventScrollChangeThumbnailRef.current = false;
|
|
76
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = null;
|
|
77
|
+
}, 1e3);
|
|
78
|
+
};
|
|
79
|
+
const scrollEvent = (value) => {
|
|
80
|
+
if (preventScrollChangeThumbnailRef.current) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const scrollPage = Math.floor(value.top / getPdfItemHeight()) + 1;
|
|
84
|
+
if (scrollPage > 0 && scrollPage !== state.currentPage) {
|
|
85
|
+
state.currentPage = scrollPage;
|
|
86
|
+
thumbnailWrapperRef.current?.scrollTo({
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
top: document.getElementById(`thumbnail-${scrollPage}`).offsetTop,
|
|
89
|
+
behavior: "smooth"
|
|
90
|
+
});
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const { run: runScrollEvent } = ahooks.useDebounceFn(scrollEvent, {
|
|
95
|
+
wait: 200
|
|
96
|
+
});
|
|
97
|
+
ahooks.useScroll(pdfPageWrapperRef, runScrollEvent);
|
|
98
|
+
const commonPdfProps = {
|
|
99
|
+
canvasBackground: backgroundColor
|
|
100
|
+
};
|
|
101
|
+
const [, { enterFullscreen }] = ahooks.useFullscreen(() => document.querySelector(".pdf-wrapper"));
|
|
102
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Root, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
103
|
+
reactPdf.Document,
|
|
104
|
+
{
|
|
105
|
+
loading: () => loading({
|
|
106
|
+
height: maxHeight
|
|
107
|
+
}),
|
|
108
|
+
file: pdfUrl,
|
|
109
|
+
onLoadSuccess: onDocumentLoadSuccess,
|
|
110
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
111
|
+
Box__default,
|
|
112
|
+
{
|
|
113
|
+
className: "pdf-wrapper",
|
|
114
|
+
sx: {
|
|
115
|
+
// default max-height: 60vh
|
|
116
|
+
maxHeight
|
|
117
|
+
},
|
|
118
|
+
...rest,
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
121
|
+
Box__default,
|
|
122
|
+
{
|
|
123
|
+
className: "pdf-page",
|
|
124
|
+
ref: pdfPageWrapperRef,
|
|
125
|
+
sx: {
|
|
126
|
+
background: backgroundColor,
|
|
127
|
+
position: "relative"
|
|
128
|
+
},
|
|
129
|
+
children: [
|
|
130
|
+
new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
131
|
+
const currentPage = index + 1;
|
|
132
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
133
|
+
reactPdf.Page,
|
|
134
|
+
{
|
|
135
|
+
pageNumber: currentPage,
|
|
136
|
+
renderTextLayer: false,
|
|
137
|
+
width: wrapperSize?.width,
|
|
138
|
+
scale: state.scale,
|
|
139
|
+
...commonPdfProps,
|
|
140
|
+
loading: () => loading({
|
|
141
|
+
height: maxHeight
|
|
142
|
+
})
|
|
143
|
+
},
|
|
144
|
+
`${pdfUrl}-${currentPage}`
|
|
145
|
+
);
|
|
146
|
+
}),
|
|
147
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box__default, { className: "pdf-page-toolbar", children: [
|
|
148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
149
|
+
IconButton__default,
|
|
150
|
+
{
|
|
151
|
+
onClick: () => {
|
|
152
|
+
if (state.scale > 0.1) {
|
|
153
|
+
state.scale -= 0.1;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ZoomOutIcon__default, {})
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
160
|
+
IconButton__default,
|
|
161
|
+
{
|
|
162
|
+
onClick: () => {
|
|
163
|
+
state.scale += 0.1;
|
|
164
|
+
},
|
|
165
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ZoomInIcon__default, {})
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default, { onClick: enterFullscreen, children: /* @__PURE__ */ jsxRuntime.jsx(FullscreenIcon__default, {}) }),
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
170
|
+
IconButton__default,
|
|
171
|
+
{
|
|
172
|
+
onClick: () => {
|
|
173
|
+
const link = document.createElement("a");
|
|
174
|
+
link.href = pdfUrl;
|
|
175
|
+
link.download = pdfUrl.split("/").pop() || "download.pdf";
|
|
176
|
+
link.click();
|
|
177
|
+
},
|
|
178
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon__default, {})
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
182
|
+
IconButton__default,
|
|
183
|
+
{
|
|
184
|
+
onClick: () => {
|
|
185
|
+
window.open(pdfUrl, "_blank");
|
|
186
|
+
},
|
|
187
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ArrowOutwardOutlinedIcon__default, {})
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
] })
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
195
|
+
Box__default,
|
|
196
|
+
{
|
|
197
|
+
className: "pdf-thumbnail",
|
|
198
|
+
ref: thumbnailWrapperRef,
|
|
199
|
+
sx: {
|
|
200
|
+
".active": {
|
|
201
|
+
border: getBorder(theme?.palette?.primary?.main),
|
|
202
|
+
".pdf-thumbnail-index": {
|
|
203
|
+
background: theme?.palette?.primary?.main
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
".no-active": {
|
|
207
|
+
border: getBorder("transparent")
|
|
208
|
+
},
|
|
209
|
+
"*": {
|
|
210
|
+
transition: "all 0.2s",
|
|
211
|
+
cursor: "pointer"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
children: new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
215
|
+
const currentPage = index + 1;
|
|
216
|
+
const key = `thumbnail-${currentPage}`;
|
|
217
|
+
const width = isMobile ? 90 : 120;
|
|
218
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
219
|
+
Box__default,
|
|
220
|
+
{
|
|
221
|
+
id: key,
|
|
222
|
+
className: `${state.currentPage === currentPage ? "active" : "no-active"}`,
|
|
223
|
+
component: "a",
|
|
224
|
+
sx: {
|
|
225
|
+
width: width + 4
|
|
226
|
+
// add border width
|
|
227
|
+
},
|
|
228
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
229
|
+
reactPdf.Thumbnail,
|
|
230
|
+
{
|
|
231
|
+
pageIndex: currentPage,
|
|
232
|
+
pageNumber: currentPage,
|
|
233
|
+
width,
|
|
234
|
+
...commonPdfProps,
|
|
235
|
+
onClick: (e) => {
|
|
236
|
+
e.stopPropagation();
|
|
237
|
+
e.preventDefault();
|
|
238
|
+
onPageChange(currentPage);
|
|
239
|
+
},
|
|
240
|
+
loading: loading({
|
|
241
|
+
height: `calc(${maxHeight} / ${isMobile ? 5 : 4})`,
|
|
242
|
+
sx: {
|
|
243
|
+
border: getBorder("transparent")
|
|
244
|
+
}
|
|
245
|
+
}),
|
|
246
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
247
|
+
Box__default,
|
|
248
|
+
{
|
|
249
|
+
className: "pdf-thumbnail-index",
|
|
250
|
+
component: "span",
|
|
251
|
+
sx: {
|
|
252
|
+
position: "absolute",
|
|
253
|
+
textAlign: "center",
|
|
254
|
+
bottom: 0,
|
|
255
|
+
left: 0,
|
|
256
|
+
right: 0,
|
|
257
|
+
color: "#fff",
|
|
258
|
+
fontSize: 13,
|
|
259
|
+
p: 0.5,
|
|
260
|
+
background: "rgba(0,0,0,0.25)"
|
|
261
|
+
},
|
|
262
|
+
children: [
|
|
263
|
+
"# ",
|
|
264
|
+
currentPage
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
`index-${currentPage}`
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
},
|
|
272
|
+
key
|
|
273
|
+
);
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
) });
|
|
282
|
+
}
|
|
283
|
+
const Root = material.styled(Box__default)`
|
|
284
|
+
.pdf-wrapper {
|
|
285
|
+
display: flex;
|
|
286
|
+
justify-content: center;
|
|
287
|
+
align-items: stretch;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.pdf-page {
|
|
291
|
+
flex: 1;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
justify-content: flex-start;
|
|
295
|
+
align-items: center;
|
|
296
|
+
overflow-y: auto;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.pdf-page-toolbar {
|
|
300
|
+
position: sticky;
|
|
301
|
+
margin-top: 16px;
|
|
302
|
+
bottom: 16px;
|
|
303
|
+
right: 0;
|
|
304
|
+
left: 0;
|
|
305
|
+
background: rgba(0, 0, 0, 0.5);
|
|
306
|
+
border-radius: 4px;
|
|
307
|
+
display: flex;
|
|
308
|
+
align-items: center;
|
|
309
|
+
padding: 2px 8px;
|
|
310
|
+
gap: 4px;
|
|
311
|
+
* {
|
|
312
|
+
color: white;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.pdf-thumbnail {
|
|
317
|
+
margin-left: 16px;
|
|
318
|
+
display: flex;
|
|
319
|
+
justify-content: flex-start;
|
|
320
|
+
align-items: center;
|
|
321
|
+
flex-direction: column;
|
|
322
|
+
gap: 16px;
|
|
323
|
+
overflow-y: auto;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.react-pdf__Page__annotations {
|
|
327
|
+
display: none !important;
|
|
328
|
+
height: 0px !important;
|
|
329
|
+
width: 0px !important;
|
|
330
|
+
}
|
|
331
|
+
`;
|
|
332
|
+
|
|
333
|
+
exports.PdfComponent = PdfComponent;
|
package/lib/index.d.cts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BoxProps } from '@mui/system';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface PdfProps extends BoxProps {
|
|
5
|
+
url: string;
|
|
6
|
+
backgroundColor?: string;
|
|
7
|
+
loading?: any;
|
|
8
|
+
maxHeight?: number | string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare function PdfComponent({ url, backgroundColor, loading, maxHeight, ...rest }: PdfProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { PdfComponent, type PdfProps };
|
package/lib/index.d.mts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BoxProps } from '@mui/system';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface PdfProps extends BoxProps {
|
|
5
|
+
url: string;
|
|
6
|
+
backgroundColor?: string;
|
|
7
|
+
loading?: any;
|
|
8
|
+
maxHeight?: number | string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare function PdfComponent({ url, backgroundColor, loading, maxHeight, ...rest }: PdfProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { PdfComponent, type PdfProps };
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BoxProps } from '@mui/system';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface PdfProps extends BoxProps {
|
|
5
|
+
url: string;
|
|
6
|
+
backgroundColor?: string;
|
|
7
|
+
loading?: any;
|
|
8
|
+
maxHeight?: number | string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare function PdfComponent({ url, backgroundColor, loading, maxHeight, ...rest }: PdfProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { PdfComponent, type PdfProps };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
const react = require('react');
|
|
5
|
+
const reactPdf = require('react-pdf');
|
|
6
|
+
const ahooks = require('ahooks');
|
|
7
|
+
const useTheme = require('@mui/material/styles/useTheme');
|
|
8
|
+
const useMediaQuery = require('@mui/material/useMediaQuery');
|
|
9
|
+
const Box = require('@mui/material/Box');
|
|
10
|
+
const Skeleton = require('@mui/material/Skeleton');
|
|
11
|
+
const IconButton = require('@mui/material/IconButton');
|
|
12
|
+
const FullscreenIcon = require('@mui/icons-material/Fullscreen');
|
|
13
|
+
const ZoomOutIcon = require('@mui/icons-material/ZoomOut');
|
|
14
|
+
const ZoomInIcon = require('@mui/icons-material/ZoomIn');
|
|
15
|
+
const DownloadIcon = require('@mui/icons-material/Download');
|
|
16
|
+
const ArrowOutwardOutlinedIcon = require('@mui/icons-material/ArrowOutwardOutlined');
|
|
17
|
+
const material = require('@mui/material');
|
|
18
|
+
require('react-pdf/dist/Page/AnnotationLayer.css');
|
|
19
|
+
require('react-pdf/dist/Page/TextLayer.css');
|
|
20
|
+
|
|
21
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
22
|
+
|
|
23
|
+
const useTheme__default = /*#__PURE__*/_interopDefaultCompat(useTheme);
|
|
24
|
+
const useMediaQuery__default = /*#__PURE__*/_interopDefaultCompat(useMediaQuery);
|
|
25
|
+
const Box__default = /*#__PURE__*/_interopDefaultCompat(Box);
|
|
26
|
+
const Skeleton__default = /*#__PURE__*/_interopDefaultCompat(Skeleton);
|
|
27
|
+
const IconButton__default = /*#__PURE__*/_interopDefaultCompat(IconButton);
|
|
28
|
+
const FullscreenIcon__default = /*#__PURE__*/_interopDefaultCompat(FullscreenIcon);
|
|
29
|
+
const ZoomOutIcon__default = /*#__PURE__*/_interopDefaultCompat(ZoomOutIcon);
|
|
30
|
+
const ZoomInIcon__default = /*#__PURE__*/_interopDefaultCompat(ZoomInIcon);
|
|
31
|
+
const DownloadIcon__default = /*#__PURE__*/_interopDefaultCompat(DownloadIcon);
|
|
32
|
+
const ArrowOutwardOutlinedIcon__default = /*#__PURE__*/_interopDefaultCompat(ArrowOutwardOutlinedIcon);
|
|
33
|
+
|
|
34
|
+
const workerSrc = `//unpkg.com/pdfjs-dist@${reactPdf.pdfjs.version}/legacy/build/pdf.worker.min.js`;
|
|
35
|
+
reactPdf.pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
36
|
+
const preventScrollChangeThumbnailTimerMap = {};
|
|
37
|
+
const getBorder = (color) => `2px solid ${color}`;
|
|
38
|
+
const defaultLoading = (props) => {
|
|
39
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Skeleton__default, { variant: "rectangular", width: "100%", ...props });
|
|
40
|
+
};
|
|
41
|
+
function PdfComponent({
|
|
42
|
+
url,
|
|
43
|
+
backgroundColor = "#fbfbfb",
|
|
44
|
+
loading = defaultLoading,
|
|
45
|
+
maxHeight = "60vh",
|
|
46
|
+
...rest
|
|
47
|
+
}) {
|
|
48
|
+
const pdfPageWrapperRef = react.useRef(null);
|
|
49
|
+
const thumbnailWrapperRef = react.useRef(null);
|
|
50
|
+
const preventScrollChangeThumbnailRef = react.useRef(false);
|
|
51
|
+
const state = ahooks.useReactive({
|
|
52
|
+
currentPage: 1,
|
|
53
|
+
totalPage: 1,
|
|
54
|
+
scale: 1
|
|
55
|
+
});
|
|
56
|
+
const wrapperSize = ahooks.useSize(pdfPageWrapperRef);
|
|
57
|
+
const theme = useTheme__default();
|
|
58
|
+
const isMobile = useMediaQuery__default(theme.breakpoints.down("sm"));
|
|
59
|
+
const pdfUrl = url;
|
|
60
|
+
const getPdfItemHeight = () => pdfPageWrapperRef.current?.children[0]?.offsetHeight;
|
|
61
|
+
const onDocumentLoadSuccess = (pdf) => {
|
|
62
|
+
state.totalPage = pdf.numPages;
|
|
63
|
+
};
|
|
64
|
+
const onPageChange = (page) => {
|
|
65
|
+
state.currentPage = page;
|
|
66
|
+
preventScrollChangeThumbnailRef.current = true;
|
|
67
|
+
const top = getPdfItemHeight() * (page - 1);
|
|
68
|
+
pdfPageWrapperRef?.current?.scrollTo({
|
|
69
|
+
top,
|
|
70
|
+
behavior: "smooth"
|
|
71
|
+
});
|
|
72
|
+
if (preventScrollChangeThumbnailTimerMap[pdfUrl])
|
|
73
|
+
clearTimeout(preventScrollChangeThumbnailTimerMap[pdfUrl]);
|
|
74
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = setTimeout(() => {
|
|
75
|
+
preventScrollChangeThumbnailRef.current = false;
|
|
76
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = null;
|
|
77
|
+
}, 1e3);
|
|
78
|
+
};
|
|
79
|
+
const scrollEvent = (value) => {
|
|
80
|
+
if (preventScrollChangeThumbnailRef.current) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const scrollPage = Math.floor(value.top / getPdfItemHeight()) + 1;
|
|
84
|
+
if (scrollPage > 0 && scrollPage !== state.currentPage) {
|
|
85
|
+
state.currentPage = scrollPage;
|
|
86
|
+
thumbnailWrapperRef.current?.scrollTo({
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
top: document.getElementById(`thumbnail-${scrollPage}`).offsetTop,
|
|
89
|
+
behavior: "smooth"
|
|
90
|
+
});
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const { run: runScrollEvent } = ahooks.useDebounceFn(scrollEvent, {
|
|
95
|
+
wait: 200
|
|
96
|
+
});
|
|
97
|
+
ahooks.useScroll(pdfPageWrapperRef, runScrollEvent);
|
|
98
|
+
const commonPdfProps = {
|
|
99
|
+
canvasBackground: backgroundColor
|
|
100
|
+
};
|
|
101
|
+
const [, { enterFullscreen }] = ahooks.useFullscreen(() => document.querySelector(".pdf-wrapper"));
|
|
102
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Root, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
103
|
+
reactPdf.Document,
|
|
104
|
+
{
|
|
105
|
+
loading: () => loading({
|
|
106
|
+
height: maxHeight
|
|
107
|
+
}),
|
|
108
|
+
file: pdfUrl,
|
|
109
|
+
onLoadSuccess: onDocumentLoadSuccess,
|
|
110
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
111
|
+
Box__default,
|
|
112
|
+
{
|
|
113
|
+
className: "pdf-wrapper",
|
|
114
|
+
sx: {
|
|
115
|
+
// default max-height: 60vh
|
|
116
|
+
maxHeight
|
|
117
|
+
},
|
|
118
|
+
...rest,
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
121
|
+
Box__default,
|
|
122
|
+
{
|
|
123
|
+
className: "pdf-page",
|
|
124
|
+
ref: pdfPageWrapperRef,
|
|
125
|
+
sx: {
|
|
126
|
+
background: backgroundColor,
|
|
127
|
+
position: "relative"
|
|
128
|
+
},
|
|
129
|
+
children: [
|
|
130
|
+
new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
131
|
+
const currentPage = index + 1;
|
|
132
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
133
|
+
reactPdf.Page,
|
|
134
|
+
{
|
|
135
|
+
pageNumber: currentPage,
|
|
136
|
+
renderTextLayer: false,
|
|
137
|
+
width: wrapperSize?.width,
|
|
138
|
+
scale: state.scale,
|
|
139
|
+
...commonPdfProps,
|
|
140
|
+
loading: () => loading({
|
|
141
|
+
height: maxHeight
|
|
142
|
+
})
|
|
143
|
+
},
|
|
144
|
+
`${pdfUrl}-${currentPage}`
|
|
145
|
+
);
|
|
146
|
+
}),
|
|
147
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box__default, { className: "pdf-page-toolbar", children: [
|
|
148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
149
|
+
IconButton__default,
|
|
150
|
+
{
|
|
151
|
+
onClick: () => {
|
|
152
|
+
if (state.scale > 0.1) {
|
|
153
|
+
state.scale -= 0.1;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ZoomOutIcon__default, {})
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
160
|
+
IconButton__default,
|
|
161
|
+
{
|
|
162
|
+
onClick: () => {
|
|
163
|
+
state.scale += 0.1;
|
|
164
|
+
},
|
|
165
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ZoomInIcon__default, {})
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default, { onClick: enterFullscreen, children: /* @__PURE__ */ jsxRuntime.jsx(FullscreenIcon__default, {}) }),
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
170
|
+
IconButton__default,
|
|
171
|
+
{
|
|
172
|
+
onClick: () => {
|
|
173
|
+
const link = document.createElement("a");
|
|
174
|
+
link.href = pdfUrl;
|
|
175
|
+
link.download = pdfUrl.split("/").pop() || "download.pdf";
|
|
176
|
+
link.click();
|
|
177
|
+
},
|
|
178
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon__default, {})
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
182
|
+
IconButton__default,
|
|
183
|
+
{
|
|
184
|
+
onClick: () => {
|
|
185
|
+
window.open(pdfUrl, "_blank");
|
|
186
|
+
},
|
|
187
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ArrowOutwardOutlinedIcon__default, {})
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
] })
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
195
|
+
Box__default,
|
|
196
|
+
{
|
|
197
|
+
className: "pdf-thumbnail",
|
|
198
|
+
ref: thumbnailWrapperRef,
|
|
199
|
+
sx: {
|
|
200
|
+
".active": {
|
|
201
|
+
border: getBorder(theme?.palette?.primary?.main),
|
|
202
|
+
".pdf-thumbnail-index": {
|
|
203
|
+
background: theme?.palette?.primary?.main
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
".no-active": {
|
|
207
|
+
border: getBorder("transparent")
|
|
208
|
+
},
|
|
209
|
+
"*": {
|
|
210
|
+
transition: "all 0.2s",
|
|
211
|
+
cursor: "pointer"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
children: new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
215
|
+
const currentPage = index + 1;
|
|
216
|
+
const key = `thumbnail-${currentPage}`;
|
|
217
|
+
const width = isMobile ? 90 : 120;
|
|
218
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
219
|
+
Box__default,
|
|
220
|
+
{
|
|
221
|
+
id: key,
|
|
222
|
+
className: `${state.currentPage === currentPage ? "active" : "no-active"}`,
|
|
223
|
+
component: "a",
|
|
224
|
+
sx: {
|
|
225
|
+
width: width + 4
|
|
226
|
+
// add border width
|
|
227
|
+
},
|
|
228
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
229
|
+
reactPdf.Thumbnail,
|
|
230
|
+
{
|
|
231
|
+
pageIndex: currentPage,
|
|
232
|
+
pageNumber: currentPage,
|
|
233
|
+
width,
|
|
234
|
+
...commonPdfProps,
|
|
235
|
+
onClick: (e) => {
|
|
236
|
+
e.stopPropagation();
|
|
237
|
+
e.preventDefault();
|
|
238
|
+
onPageChange(currentPage);
|
|
239
|
+
},
|
|
240
|
+
loading: loading({
|
|
241
|
+
height: `calc(${maxHeight} / ${isMobile ? 5 : 4})`,
|
|
242
|
+
sx: {
|
|
243
|
+
border: getBorder("transparent")
|
|
244
|
+
}
|
|
245
|
+
}),
|
|
246
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
247
|
+
Box__default,
|
|
248
|
+
{
|
|
249
|
+
className: "pdf-thumbnail-index",
|
|
250
|
+
component: "span",
|
|
251
|
+
sx: {
|
|
252
|
+
position: "absolute",
|
|
253
|
+
textAlign: "center",
|
|
254
|
+
bottom: 0,
|
|
255
|
+
left: 0,
|
|
256
|
+
right: 0,
|
|
257
|
+
color: "#fff",
|
|
258
|
+
fontSize: 13,
|
|
259
|
+
p: 0.5,
|
|
260
|
+
background: "rgba(0,0,0,0.25)"
|
|
261
|
+
},
|
|
262
|
+
children: [
|
|
263
|
+
"# ",
|
|
264
|
+
currentPage
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
`index-${currentPage}`
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
},
|
|
272
|
+
key
|
|
273
|
+
);
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
) });
|
|
282
|
+
}
|
|
283
|
+
const Root = material.styled(Box__default)`
|
|
284
|
+
.pdf-wrapper {
|
|
285
|
+
display: flex;
|
|
286
|
+
justify-content: center;
|
|
287
|
+
align-items: stretch;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.pdf-page {
|
|
291
|
+
flex: 1;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
justify-content: flex-start;
|
|
295
|
+
align-items: center;
|
|
296
|
+
overflow-y: auto;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.pdf-page-toolbar {
|
|
300
|
+
position: sticky;
|
|
301
|
+
margin-top: 16px;
|
|
302
|
+
bottom: 16px;
|
|
303
|
+
right: 0;
|
|
304
|
+
left: 0;
|
|
305
|
+
background: rgba(0, 0, 0, 0.5);
|
|
306
|
+
border-radius: 4px;
|
|
307
|
+
display: flex;
|
|
308
|
+
align-items: center;
|
|
309
|
+
padding: 2px 8px;
|
|
310
|
+
gap: 4px;
|
|
311
|
+
* {
|
|
312
|
+
color: white;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.pdf-thumbnail {
|
|
317
|
+
margin-left: 16px;
|
|
318
|
+
display: flex;
|
|
319
|
+
justify-content: flex-start;
|
|
320
|
+
align-items: center;
|
|
321
|
+
flex-direction: column;
|
|
322
|
+
gap: 16px;
|
|
323
|
+
overflow-y: auto;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.react-pdf__Page__annotations {
|
|
327
|
+
display: none !important;
|
|
328
|
+
height: 0px !important;
|
|
329
|
+
width: 0px !important;
|
|
330
|
+
}
|
|
331
|
+
`;
|
|
332
|
+
|
|
333
|
+
exports.PdfComponent = PdfComponent;
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { pdfjs, Document, Page, Thumbnail } from 'react-pdf';
|
|
4
|
+
import { useReactive, useSize, useDebounceFn, useScroll, useFullscreen } from 'ahooks';
|
|
5
|
+
import useTheme from '@mui/material/styles/useTheme';
|
|
6
|
+
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
7
|
+
import Box from '@mui/material/Box';
|
|
8
|
+
import Skeleton from '@mui/material/Skeleton';
|
|
9
|
+
import IconButton from '@mui/material/IconButton';
|
|
10
|
+
import FullscreenIcon from '@mui/icons-material/Fullscreen';
|
|
11
|
+
import ZoomOutIcon from '@mui/icons-material/ZoomOut';
|
|
12
|
+
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
|
13
|
+
import DownloadIcon from '@mui/icons-material/Download';
|
|
14
|
+
import ArrowOutwardOutlinedIcon from '@mui/icons-material/ArrowOutwardOutlined';
|
|
15
|
+
import { styled } from '@mui/material';
|
|
16
|
+
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
|
17
|
+
import 'react-pdf/dist/Page/TextLayer.css';
|
|
18
|
+
|
|
19
|
+
const workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.js`;
|
|
20
|
+
pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
21
|
+
const preventScrollChangeThumbnailTimerMap = {};
|
|
22
|
+
const getBorder = (color) => `2px solid ${color}`;
|
|
23
|
+
const defaultLoading = (props) => {
|
|
24
|
+
return /* @__PURE__ */ jsx(Skeleton, { variant: "rectangular", width: "100%", ...props });
|
|
25
|
+
};
|
|
26
|
+
function PdfComponent({
|
|
27
|
+
url,
|
|
28
|
+
backgroundColor = "#fbfbfb",
|
|
29
|
+
loading = defaultLoading,
|
|
30
|
+
maxHeight = "60vh",
|
|
31
|
+
...rest
|
|
32
|
+
}) {
|
|
33
|
+
const pdfPageWrapperRef = useRef(null);
|
|
34
|
+
const thumbnailWrapperRef = useRef(null);
|
|
35
|
+
const preventScrollChangeThumbnailRef = useRef(false);
|
|
36
|
+
const state = useReactive({
|
|
37
|
+
currentPage: 1,
|
|
38
|
+
totalPage: 1,
|
|
39
|
+
scale: 1
|
|
40
|
+
});
|
|
41
|
+
const wrapperSize = useSize(pdfPageWrapperRef);
|
|
42
|
+
const theme = useTheme();
|
|
43
|
+
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
|
44
|
+
const pdfUrl = url;
|
|
45
|
+
const getPdfItemHeight = () => pdfPageWrapperRef.current?.children[0]?.offsetHeight;
|
|
46
|
+
const onDocumentLoadSuccess = (pdf) => {
|
|
47
|
+
state.totalPage = pdf.numPages;
|
|
48
|
+
};
|
|
49
|
+
const onPageChange = (page) => {
|
|
50
|
+
state.currentPage = page;
|
|
51
|
+
preventScrollChangeThumbnailRef.current = true;
|
|
52
|
+
const top = getPdfItemHeight() * (page - 1);
|
|
53
|
+
pdfPageWrapperRef?.current?.scrollTo({
|
|
54
|
+
top,
|
|
55
|
+
behavior: "smooth"
|
|
56
|
+
});
|
|
57
|
+
if (preventScrollChangeThumbnailTimerMap[pdfUrl])
|
|
58
|
+
clearTimeout(preventScrollChangeThumbnailTimerMap[pdfUrl]);
|
|
59
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = setTimeout(() => {
|
|
60
|
+
preventScrollChangeThumbnailRef.current = false;
|
|
61
|
+
preventScrollChangeThumbnailTimerMap[pdfUrl] = null;
|
|
62
|
+
}, 1e3);
|
|
63
|
+
};
|
|
64
|
+
const scrollEvent = (value) => {
|
|
65
|
+
if (preventScrollChangeThumbnailRef.current) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const scrollPage = Math.floor(value.top / getPdfItemHeight()) + 1;
|
|
69
|
+
if (scrollPage > 0 && scrollPage !== state.currentPage) {
|
|
70
|
+
state.currentPage = scrollPage;
|
|
71
|
+
thumbnailWrapperRef.current?.scrollTo({
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
top: document.getElementById(`thumbnail-${scrollPage}`).offsetTop,
|
|
74
|
+
behavior: "smooth"
|
|
75
|
+
});
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const { run: runScrollEvent } = useDebounceFn(scrollEvent, {
|
|
80
|
+
wait: 200
|
|
81
|
+
});
|
|
82
|
+
useScroll(pdfPageWrapperRef, runScrollEvent);
|
|
83
|
+
const commonPdfProps = {
|
|
84
|
+
canvasBackground: backgroundColor
|
|
85
|
+
};
|
|
86
|
+
const [, { enterFullscreen }] = useFullscreen(() => document.querySelector(".pdf-wrapper"));
|
|
87
|
+
return /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx(
|
|
88
|
+
Document,
|
|
89
|
+
{
|
|
90
|
+
loading: () => loading({
|
|
91
|
+
height: maxHeight
|
|
92
|
+
}),
|
|
93
|
+
file: pdfUrl,
|
|
94
|
+
onLoadSuccess: onDocumentLoadSuccess,
|
|
95
|
+
children: /* @__PURE__ */ jsxs(
|
|
96
|
+
Box,
|
|
97
|
+
{
|
|
98
|
+
className: "pdf-wrapper",
|
|
99
|
+
sx: {
|
|
100
|
+
// default max-height: 60vh
|
|
101
|
+
maxHeight
|
|
102
|
+
},
|
|
103
|
+
...rest,
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsxs(
|
|
106
|
+
Box,
|
|
107
|
+
{
|
|
108
|
+
className: "pdf-page",
|
|
109
|
+
ref: pdfPageWrapperRef,
|
|
110
|
+
sx: {
|
|
111
|
+
background: backgroundColor,
|
|
112
|
+
position: "relative"
|
|
113
|
+
},
|
|
114
|
+
children: [
|
|
115
|
+
new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
116
|
+
const currentPage = index + 1;
|
|
117
|
+
return /* @__PURE__ */ jsx(
|
|
118
|
+
Page,
|
|
119
|
+
{
|
|
120
|
+
pageNumber: currentPage,
|
|
121
|
+
renderTextLayer: false,
|
|
122
|
+
width: wrapperSize?.width,
|
|
123
|
+
scale: state.scale,
|
|
124
|
+
...commonPdfProps,
|
|
125
|
+
loading: () => loading({
|
|
126
|
+
height: maxHeight
|
|
127
|
+
})
|
|
128
|
+
},
|
|
129
|
+
`${pdfUrl}-${currentPage}`
|
|
130
|
+
);
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ jsxs(Box, { className: "pdf-page-toolbar", children: [
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
IconButton,
|
|
135
|
+
{
|
|
136
|
+
onClick: () => {
|
|
137
|
+
if (state.scale > 0.1) {
|
|
138
|
+
state.scale -= 0.1;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
children: /* @__PURE__ */ jsx(ZoomOutIcon, {})
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
/* @__PURE__ */ jsx(
|
|
145
|
+
IconButton,
|
|
146
|
+
{
|
|
147
|
+
onClick: () => {
|
|
148
|
+
state.scale += 0.1;
|
|
149
|
+
},
|
|
150
|
+
children: /* @__PURE__ */ jsx(ZoomInIcon, {})
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
/* @__PURE__ */ jsx(IconButton, { onClick: enterFullscreen, children: /* @__PURE__ */ jsx(FullscreenIcon, {}) }),
|
|
154
|
+
/* @__PURE__ */ jsx(
|
|
155
|
+
IconButton,
|
|
156
|
+
{
|
|
157
|
+
onClick: () => {
|
|
158
|
+
const link = document.createElement("a");
|
|
159
|
+
link.href = pdfUrl;
|
|
160
|
+
link.download = pdfUrl.split("/").pop() || "download.pdf";
|
|
161
|
+
link.click();
|
|
162
|
+
},
|
|
163
|
+
children: /* @__PURE__ */ jsx(DownloadIcon, {})
|
|
164
|
+
}
|
|
165
|
+
),
|
|
166
|
+
/* @__PURE__ */ jsx(
|
|
167
|
+
IconButton,
|
|
168
|
+
{
|
|
169
|
+
onClick: () => {
|
|
170
|
+
window.open(pdfUrl, "_blank");
|
|
171
|
+
},
|
|
172
|
+
children: /* @__PURE__ */ jsx(ArrowOutwardOutlinedIcon, {})
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
] })
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
/* @__PURE__ */ jsx(
|
|
180
|
+
Box,
|
|
181
|
+
{
|
|
182
|
+
className: "pdf-thumbnail",
|
|
183
|
+
ref: thumbnailWrapperRef,
|
|
184
|
+
sx: {
|
|
185
|
+
".active": {
|
|
186
|
+
border: getBorder(theme?.palette?.primary?.main),
|
|
187
|
+
".pdf-thumbnail-index": {
|
|
188
|
+
background: theme?.palette?.primary?.main
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
".no-active": {
|
|
192
|
+
border: getBorder("transparent")
|
|
193
|
+
},
|
|
194
|
+
"*": {
|
|
195
|
+
transition: "all 0.2s",
|
|
196
|
+
cursor: "pointer"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
children: new Array(state.totalPage || 0).fill(0).map((_, index) => {
|
|
200
|
+
const currentPage = index + 1;
|
|
201
|
+
const key = `thumbnail-${currentPage}`;
|
|
202
|
+
const width = isMobile ? 90 : 120;
|
|
203
|
+
return /* @__PURE__ */ jsx(
|
|
204
|
+
Box,
|
|
205
|
+
{
|
|
206
|
+
id: key,
|
|
207
|
+
className: `${state.currentPage === currentPage ? "active" : "no-active"}`,
|
|
208
|
+
component: "a",
|
|
209
|
+
sx: {
|
|
210
|
+
width: width + 4
|
|
211
|
+
// add border width
|
|
212
|
+
},
|
|
213
|
+
children: /* @__PURE__ */ jsx(
|
|
214
|
+
Thumbnail,
|
|
215
|
+
{
|
|
216
|
+
pageIndex: currentPage,
|
|
217
|
+
pageNumber: currentPage,
|
|
218
|
+
width,
|
|
219
|
+
...commonPdfProps,
|
|
220
|
+
onClick: (e) => {
|
|
221
|
+
e.stopPropagation();
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
onPageChange(currentPage);
|
|
224
|
+
},
|
|
225
|
+
loading: loading({
|
|
226
|
+
height: `calc(${maxHeight} / ${isMobile ? 5 : 4})`,
|
|
227
|
+
sx: {
|
|
228
|
+
border: getBorder("transparent")
|
|
229
|
+
}
|
|
230
|
+
}),
|
|
231
|
+
children: /* @__PURE__ */ jsxs(
|
|
232
|
+
Box,
|
|
233
|
+
{
|
|
234
|
+
className: "pdf-thumbnail-index",
|
|
235
|
+
component: "span",
|
|
236
|
+
sx: {
|
|
237
|
+
position: "absolute",
|
|
238
|
+
textAlign: "center",
|
|
239
|
+
bottom: 0,
|
|
240
|
+
left: 0,
|
|
241
|
+
right: 0,
|
|
242
|
+
color: "#fff",
|
|
243
|
+
fontSize: 13,
|
|
244
|
+
p: 0.5,
|
|
245
|
+
background: "rgba(0,0,0,0.25)"
|
|
246
|
+
},
|
|
247
|
+
children: [
|
|
248
|
+
"# ",
|
|
249
|
+
currentPage
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
`index-${currentPage}`
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
},
|
|
257
|
+
key
|
|
258
|
+
);
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
) });
|
|
267
|
+
}
|
|
268
|
+
const Root = styled(Box)`
|
|
269
|
+
.pdf-wrapper {
|
|
270
|
+
display: flex;
|
|
271
|
+
justify-content: center;
|
|
272
|
+
align-items: stretch;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.pdf-page {
|
|
276
|
+
flex: 1;
|
|
277
|
+
display: flex;
|
|
278
|
+
flex-direction: column;
|
|
279
|
+
justify-content: flex-start;
|
|
280
|
+
align-items: center;
|
|
281
|
+
overflow-y: auto;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.pdf-page-toolbar {
|
|
285
|
+
position: sticky;
|
|
286
|
+
margin-top: 16px;
|
|
287
|
+
bottom: 16px;
|
|
288
|
+
right: 0;
|
|
289
|
+
left: 0;
|
|
290
|
+
background: rgba(0, 0, 0, 0.5);
|
|
291
|
+
border-radius: 4px;
|
|
292
|
+
display: flex;
|
|
293
|
+
align-items: center;
|
|
294
|
+
padding: 2px 8px;
|
|
295
|
+
gap: 4px;
|
|
296
|
+
* {
|
|
297
|
+
color: white;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.pdf-thumbnail {
|
|
302
|
+
margin-left: 16px;
|
|
303
|
+
display: flex;
|
|
304
|
+
justify-content: flex-start;
|
|
305
|
+
align-items: center;
|
|
306
|
+
flex-direction: column;
|
|
307
|
+
gap: 16px;
|
|
308
|
+
overflow-y: auto;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.react-pdf__Page__annotations {
|
|
312
|
+
display: none !important;
|
|
313
|
+
height: 0px !important;
|
|
314
|
+
width: 0px !important;
|
|
315
|
+
}
|
|
316
|
+
`;
|
|
317
|
+
|
|
318
|
+
export { PdfComponent };
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blocklet/pdf",
|
|
3
|
+
"version": "1.6.61",
|
|
4
|
+
"description": "blocklet pdf component",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"require": "./lib/index.cjs",
|
|
12
|
+
"import": "./lib/index.mjs",
|
|
13
|
+
"types": "./lib/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./lib/": "./lib/"
|
|
16
|
+
},
|
|
17
|
+
"main": "./lib/index.cjs",
|
|
18
|
+
"module": "./lib/index.mjs",
|
|
19
|
+
"types": "./lib/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"lib",
|
|
22
|
+
"*.d.ts"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"coverage": "yarn test -- --coverage",
|
|
26
|
+
"test": "vitest tests",
|
|
27
|
+
"build": "unbuild",
|
|
28
|
+
"build:watch": "npx nodemon --ext 'ts,tsx,json,js,jsx' --exec 'yarn run build' --ignore 'lib/*' ",
|
|
29
|
+
"dev": "yarn run build:watch",
|
|
30
|
+
"prepublish": "yarn run build",
|
|
31
|
+
"prebuild:dep": "yarn run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"blocklet",
|
|
35
|
+
"pdf"
|
|
36
|
+
],
|
|
37
|
+
"author": "arcblock <blocklet@arcblock.io> https://github.com/blocklet",
|
|
38
|
+
"license": "ISC",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@mui/icons-material": "^5.15.4",
|
|
41
|
+
"@mui/material": "^5.15.4",
|
|
42
|
+
"@mui/system": "^5.15.4",
|
|
43
|
+
"ahooks": "^3.7.8",
|
|
44
|
+
"react": "^18.2.0",
|
|
45
|
+
"react-pdf": "^7.7.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
49
|
+
"@types/express": "^4.17.21",
|
|
50
|
+
"@types/lodash": "^4.14.202",
|
|
51
|
+
"@types/mime-types": "^2.1.4",
|
|
52
|
+
"@types/node": "^20.10.7",
|
|
53
|
+
"@types/react": "^18.2.47",
|
|
54
|
+
"@types/url-join": "^4.0.3",
|
|
55
|
+
"@vitest/coverage-c8": "^0.33.0",
|
|
56
|
+
"jsdom": "^22.1.0",
|
|
57
|
+
"typescript": "^5.3.3",
|
|
58
|
+
"unbuild": "^2.0.0",
|
|
59
|
+
"vitest": "^1.1.3",
|
|
60
|
+
"vitest-fetch-mock": "^0.2.2"
|
|
61
|
+
},
|
|
62
|
+
"gitHead": "c48a7dafae8605afaca690f4b1aeb70976f965f2"
|
|
63
|
+
}
|