genus-pdf-viewer 0.1.13 → 0.2.1
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/README.md +128 -63
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/{workers → dist}/pdf.worker.min.mjs +0 -0
- package/dist/styles.css +132 -0
- package/dist/styles.d.ts +2 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +212 -0
- package/dist/styles.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/viewer.d.ts +27 -0
- package/dist/viewer.d.ts.map +1 -0
- package/dist/viewer.js +678 -0
- package/dist/viewer.js.map +1 -0
- package/package.json +51 -20
- package/fesm2022/genus-pdf-viewer.mjs +0 -1346
- package/fesm2022/genus-pdf-viewer.mjs.map +0 -1
- package/genus-pdf-viewer-0.1.13.tgz +0 -0
- package/index.d.ts +0 -119
- package/schematics/collection.json +0 -10
- package/schematics/ng-add/index.js +0 -171
- package/schematics/ng-add/schema.json +0 -27
package/README.md
CHANGED
|
@@ -1,96 +1,161 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `genus-pdf-viewer`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-agnostic PDF viewer built on `pdfjs-dist` with a custom element and a small TypeScript API.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i pdfjs-dist
|
|
9
|
-
```
|
|
5
|
+
## Highlights
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
- Responsive toolbar that wraps cleanly on smaller screens
|
|
8
|
+
- Continuous-scroll document mode for reader-style PDFs
|
|
9
|
+
- Canvas-based rendering with packaged download controls
|
|
10
|
+
- Works as either a custom element or a JS API mount
|
|
12
11
|
|
|
13
|
-
##
|
|
12
|
+
## Install
|
|
14
13
|
|
|
15
14
|
```bash
|
|
16
|
-
|
|
15
|
+
npm install genus-pdf-viewer
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
`
|
|
20
|
-
- add `provideGenusPdfViewer()` to your app config when `app.config.ts` is found
|
|
21
|
-
- copy `pdf.worker.min.js` and `pdf.worker.min.mjs` to your app assets/public path
|
|
18
|
+
The package ships `pdf.worker.min.mjs` and resolves it automatically from the built package. Override `workerSrc` only if your app needs a custom asset location.
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
- `--project <name>` target a specific Angular app in a workspace
|
|
25
|
-
- `--skipWorkerCopy` skip worker file copy
|
|
26
|
-
- `--overwriteWorker` replace existing worker file
|
|
20
|
+
## Breaking Change
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
`0.2.0` replaces the older Angular-specific `0.1.x` package with a framework-agnostic runtime. If you still need the Angular library API from npm, stay on `0.1.13` or earlier.
|
|
29
23
|
|
|
30
|
-
|
|
24
|
+
## TypeScript Usage
|
|
31
25
|
|
|
32
26
|
```ts
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
27
|
+
import { createGenusPdfViewer } from "genus-pdf-viewer";
|
|
28
|
+
|
|
29
|
+
const root = document.getElementById("pdf-root");
|
|
30
|
+
|
|
31
|
+
if (root) {
|
|
32
|
+
const viewer = createGenusPdfViewer(root, {
|
|
33
|
+
src: "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf",
|
|
34
|
+
title: "Example PDF",
|
|
35
|
+
fit: "width",
|
|
36
|
+
continuous: true,
|
|
37
|
+
showToolbar: true,
|
|
38
|
+
zoomStep: 0.15,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
viewer.addEventListener("genus-ready", (event) => {
|
|
42
|
+
console.log("ready", event.detail.pageCount);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
47
45
|
```
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
- The package ships its own worker at `workers/pdf.worker.min.mjs` and uses it by default.
|
|
51
|
-
- The provider then falls back to in-package fake-worker bootstrap, and finally tries `/assets/pdf.worker.min.js` or `/assets/pdf.worker.min.mjs`.
|
|
52
|
-
- You can still override `workerSrc` if your app needs a custom location.
|
|
53
|
-
- Optional CMaps: copy `node_modules/pdfjs-dist/cmaps` to `src/assets/cmaps/` and set `cMapUrl`/`cMapPacked` if you enable text layer.
|
|
54
|
-
|
|
55
|
-
Manual alternative (not recommended): set `GlobalWorkerOptions.workerSrc` yourself at bootstrap.
|
|
47
|
+
## Custom Element
|
|
56
48
|
|
|
57
|
-
|
|
49
|
+
Register the element yourself when you want to use declarative markup without first calling `createGenusPdfViewer()`.
|
|
58
50
|
|
|
59
51
|
```ts
|
|
60
|
-
import {
|
|
52
|
+
import { defineGenusPdfViewerElement } from "genus-pdf-viewer";
|
|
53
|
+
|
|
54
|
+
defineGenusPdfViewerElement();
|
|
61
55
|
```
|
|
62
56
|
|
|
63
57
|
```html
|
|
64
58
|
<genus-pdf-viewer
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
src="https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf"
|
|
60
|
+
title="Example PDF"
|
|
61
|
+
page="1"
|
|
62
|
+
zoom="1"
|
|
63
|
+
fit="width"
|
|
64
|
+
continuous="true"
|
|
65
|
+
toolbar="true"
|
|
66
|
+
download="true"
|
|
67
|
+
></genus-pdf-viewer>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
`createGenusPdfViewer(container, config)` appends and returns a `GenusPdfViewerElement`.
|
|
73
|
+
|
|
74
|
+
Config fields:
|
|
75
|
+
|
|
76
|
+
- `src`: `string | URL | Uint8Array | Blob`
|
|
77
|
+
- `title?`: custom download and toolbar title
|
|
78
|
+
- `page?`, `zoom?`, `minZoom?`, `maxZoom?`, `zoomStep?`
|
|
79
|
+
- `fit?`: `"width" | "page" | "none"`
|
|
80
|
+
- `continuous?`, `showToolbar?`, `allowDownload?`
|
|
81
|
+
- `workerSrc?`: override the default worker URL
|
|
82
|
+
- `withCredentials?`, `httpHeaders?`: network request options for URL sources
|
|
83
|
+
|
|
84
|
+
Element methods:
|
|
85
|
+
|
|
86
|
+
- `configure(config)`
|
|
87
|
+
- `reload()`
|
|
88
|
+
- `goToPage(page)`
|
|
89
|
+
- `nextPage()`
|
|
90
|
+
- `prevPage()`
|
|
91
|
+
- `setZoom(zoom)`
|
|
92
|
+
- `zoomIn()`
|
|
93
|
+
- `zoomOut()`
|
|
94
|
+
- `download()`
|
|
95
|
+
- `destroy()`
|
|
96
|
+
|
|
97
|
+
## Events
|
|
98
|
+
|
|
99
|
+
The viewer emits bubbling custom events:
|
|
100
|
+
|
|
101
|
+
- `genus-ready`
|
|
102
|
+
- `genus-pagechange`
|
|
103
|
+
- `genus-zoomchange`
|
|
104
|
+
- `genus-error`
|
|
105
|
+
|
|
106
|
+
## Package Exports
|
|
107
|
+
|
|
108
|
+
- `genus-pdf-viewer`: main TypeScript and custom-element API
|
|
109
|
+
- `genus-pdf-viewer/pdf.worker.min.mjs`: worker asset if you need to host it yourself
|
|
110
|
+
- `genus-pdf-viewer/styles.css`: packaged stylesheet export
|
|
111
|
+
|
|
112
|
+
## Angular / Vite Setup
|
|
113
|
+
|
|
114
|
+
If your Angular app is using Vite-based dev/build tooling, prefer the JS API and pass a worker URL from the app's own `pdfjs-dist` install so the API and worker versions always match.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { createGenusPdfViewer } from "genus-pdf-viewer";
|
|
118
|
+
import workerUrl from "pdfjs-dist/build/pdf.worker.min.mjs?url";
|
|
119
|
+
|
|
120
|
+
const host = document.getElementById("pdf-root");
|
|
121
|
+
|
|
122
|
+
if (host) {
|
|
123
|
+
createGenusPdfViewer(host, {
|
|
124
|
+
src: pdfUrl,
|
|
125
|
+
title: "My PDF",
|
|
126
|
+
fit: "width",
|
|
127
|
+
continuous: true,
|
|
128
|
+
showToolbar: true,
|
|
129
|
+
zoomStep: 0.15,
|
|
130
|
+
workerSrc: workerUrl,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
70
133
|
```
|
|
71
134
|
|
|
72
|
-
|
|
73
|
-
Additional network inputs: `withCredentials`, `httpHeaders`, `allowIframeFallback`.
|
|
135
|
+
This is the setup used in `carewall_genusconnect` to avoid worker-path mismatches and fake-worker fallback.
|
|
74
136
|
|
|
75
|
-
|
|
137
|
+
## Demo
|
|
76
138
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- Automatic iframe fallback when CORS/network blocks pdf.js byte access.
|
|
139
|
+
```bash
|
|
140
|
+
npm run build
|
|
141
|
+
npm run demo:serve
|
|
142
|
+
```
|
|
82
143
|
|
|
83
|
-
|
|
144
|
+
Open `http://127.0.0.1:4175/examples/`.
|
|
145
|
+
|
|
146
|
+
## Validate
|
|
84
147
|
|
|
85
148
|
```bash
|
|
86
|
-
npm run
|
|
87
|
-
|
|
149
|
+
npm run typecheck
|
|
150
|
+
npm run test
|
|
151
|
+
npm run build
|
|
152
|
+
npm pack --dry-run
|
|
88
153
|
```
|
|
89
154
|
|
|
90
|
-
|
|
155
|
+
## Publish
|
|
91
156
|
|
|
92
|
-
|
|
157
|
+
This repo is configured for the existing public npm package `genus-pdf-viewer`.
|
|
93
158
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
159
|
+
```bash
|
|
160
|
+
npm publish
|
|
161
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createGenusPdfViewer, defineGenusPdfViewerElement, GenusPdfViewerElement, } from "./viewer.js";
|
|
2
|
+
export type { GenusPdfViewerConfig, GenusPdfViewerErrorEventDetail, GenusPdfViewerEventMap, GenusPdfViewerFit, GenusPdfViewerPageChangeEventDetail, GenusPdfViewerReadyEventDetail, GenusPdfViewerSource, GenusPdfViewerZoomChangeEventDetail, } from "./types.js";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,sBAAsB,EACtB,iBAAiB,EACjB,mCAAmC,EACnC,8BAA8B,EAC9B,oBAAoB,EACpB,mCAAmC,GACpC,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
File without changes
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
color: #0f172a;
|
|
4
|
+
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
* {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.shell {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: 12px;
|
|
15
|
+
width: 100%;
|
|
16
|
+
min-height: 320px;
|
|
17
|
+
background: #f8fafc;
|
|
18
|
+
border: 1px solid #dbe4ee;
|
|
19
|
+
border-radius: 18px;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.toolbar {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 8px;
|
|
27
|
+
padding: 10px 12px;
|
|
28
|
+
background: rgba(255, 255, 255, 0.92);
|
|
29
|
+
border-bottom: 1px solid #dbe4ee;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.toolbar[hidden] {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.title {
|
|
37
|
+
font-size: 14px;
|
|
38
|
+
font-weight: 700;
|
|
39
|
+
color: #334155;
|
|
40
|
+
margin-right: auto;
|
|
41
|
+
min-width: 0;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.toolbar button {
|
|
48
|
+
appearance: none;
|
|
49
|
+
border: 1px solid #cbd5e1;
|
|
50
|
+
background: #ffffff;
|
|
51
|
+
color: #0f172a;
|
|
52
|
+
border-radius: 999px;
|
|
53
|
+
min-width: 36px;
|
|
54
|
+
height: 36px;
|
|
55
|
+
padding: 0 12px;
|
|
56
|
+
font: inherit;
|
|
57
|
+
font-weight: 700;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.toolbar button:disabled {
|
|
62
|
+
opacity: 0.45;
|
|
63
|
+
cursor: not-allowed;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.toolbar button.primary {
|
|
67
|
+
background: #0f766e;
|
|
68
|
+
border-color: #0f766e;
|
|
69
|
+
color: #f8fafc;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.toolbar .value {
|
|
73
|
+
min-width: 56px;
|
|
74
|
+
text-align: center;
|
|
75
|
+
font-size: 13px;
|
|
76
|
+
color: #475569;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.stage {
|
|
80
|
+
position: relative;
|
|
81
|
+
min-height: 320px;
|
|
82
|
+
max-height: 80vh;
|
|
83
|
+
overflow: auto;
|
|
84
|
+
background:
|
|
85
|
+
radial-gradient(circle at top, rgba(15, 118, 110, 0.08), transparent 22%),
|
|
86
|
+
#eef2f7;
|
|
87
|
+
padding: 16px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.stage.single {
|
|
91
|
+
display: grid;
|
|
92
|
+
place-items: center;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.page-stack {
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-direction: column;
|
|
98
|
+
gap: 16px;
|
|
99
|
+
align-items: center;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.page {
|
|
103
|
+
background: #ffffff;
|
|
104
|
+
border-radius: 8px;
|
|
105
|
+
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.12);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
canvas {
|
|
109
|
+
display: block;
|
|
110
|
+
max-width: 100%;
|
|
111
|
+
height: auto;
|
|
112
|
+
border-radius: 8px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.status {
|
|
116
|
+
position: absolute;
|
|
117
|
+
inset: 16px;
|
|
118
|
+
display: none;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
padding: 24px;
|
|
122
|
+
border-radius: 12px;
|
|
123
|
+
background: rgba(248, 250, 252, 0.92);
|
|
124
|
+
color: #475569;
|
|
125
|
+
text-align: center;
|
|
126
|
+
font-size: 14px;
|
|
127
|
+
line-height: 1.5;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.status.visible {
|
|
131
|
+
display: flex;
|
|
132
|
+
}
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const VIEWER_STYLES = "\n:host {\n display: block;\n color: #0f172a;\n font-family: \"Segoe UI\", \"Helvetica Neue\", Arial, sans-serif;\n}\n\n* {\n box-sizing: border-box;\n}\n\n.shell {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n min-height: 320px;\n background: #f8fafc;\n border: 1px solid #dbe4ee;\n border-radius: 18px;\n overflow: hidden;\n}\n\n.toolbar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.92);\n border-bottom: 1px solid #dbe4ee;\n position: sticky;\n top: 0;\n z-index: 2;\n backdrop-filter: blur(14px);\n}\n\n.toolbar[hidden] {\n display: none;\n}\n\n.title {\n flex: 1 1 240px;\n font-size: 14px;\n font-weight: 700;\n color: #334155;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.toolbar-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.toolbar button {\n appearance: none;\n border: 1px solid #cbd5e1;\n background: #ffffff;\n color: #0f172a;\n border-radius: 999px;\n min-width: 36px;\n height: 36px;\n padding: 0 12px;\n font: inherit;\n font-weight: 700;\n cursor: pointer;\n transition:\n transform 140ms ease,\n background-color 180ms ease,\n border-color 180ms ease,\n box-shadow 180ms ease;\n}\n\n.toolbar button:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 10px 18px rgba(15, 23, 42, 0.08);\n}\n\n.toolbar button:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.toolbar button:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n\n.toolbar button.primary {\n background: #0f766e;\n border-color: #0f766e;\n color: #f8fafc;\n}\n\n.toolbar .value {\n min-width: 68px;\n text-align: center;\n font-size: 13px;\n color: #475569;\n}\n\n.stage {\n position: relative;\n min-height: 320px;\n max-height: 80vh;\n overflow: auto;\n scroll-behavior: smooth;\n overscroll-behavior: contain;\n background:\n radial-gradient(circle at top, rgba(15, 118, 110, 0.08), transparent 22%),\n #eef2f7;\n padding: 16px;\n}\n\n.stage.single {\n display: grid;\n place-items: center;\n}\n\n.page-stack {\n display: flex;\n flex-direction: column;\n gap: 16px;\n align-items: center;\n}\n\n.page {\n background: #ffffff;\n border-radius: 8px;\n box-shadow: 0 12px 30px rgba(15, 23, 42, 0.12);\n opacity: 1;\n transform: translateY(0) scale(1);\n transition:\n opacity 220ms ease,\n transform 220ms ease,\n box-shadow 220ms ease;\n}\n\n.page.entering {\n opacity: 0;\n transform: translateY(16px) scale(0.985);\n}\n\ncanvas {\n display: block;\n max-width: 100%;\n height: auto;\n border-radius: 8px;\n transition: filter 180ms ease;\n}\n\n.status {\n position: absolute;\n inset: 16px;\n display: none;\n align-items: center;\n justify-content: center;\n padding: 24px;\n border-radius: 12px;\n background: rgba(248, 250, 252, 0.92);\n color: #475569;\n text-align: center;\n font-size: 14px;\n line-height: 1.5;\n}\n\n.status.visible {\n display: flex;\n}\n\n@media (max-width: 720px) {\n .toolbar {\n align-items: stretch;\n }\n\n .title {\n flex-basis: 100%;\n }\n\n .toolbar-group {\n width: 100%;\n justify-content: flex-start;\n }\n\n .toolbar button {\n min-height: 40px;\n }\n\n .stage {\n max-height: none;\n min-height: 60vh;\n padding: 12px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .toolbar button,\n .page,\n canvas {\n transition: none;\n }\n\n .stage {\n scroll-behavior: auto;\n }\n}\n";
|
|
2
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,8hHAkNzB,CAAC"}
|
package/dist/styles.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
export const VIEWER_STYLES = `
|
|
2
|
+
:host {
|
|
3
|
+
display: block;
|
|
4
|
+
color: #0f172a;
|
|
5
|
+
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
* {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.shell {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: 12px;
|
|
16
|
+
width: 100%;
|
|
17
|
+
min-height: 320px;
|
|
18
|
+
background: #f8fafc;
|
|
19
|
+
border: 1px solid #dbe4ee;
|
|
20
|
+
border-radius: 18px;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.toolbar {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
flex-wrap: wrap;
|
|
28
|
+
gap: 10px;
|
|
29
|
+
padding: 10px 12px;
|
|
30
|
+
background: rgba(255, 255, 255, 0.92);
|
|
31
|
+
border-bottom: 1px solid #dbe4ee;
|
|
32
|
+
position: sticky;
|
|
33
|
+
top: 0;
|
|
34
|
+
z-index: 2;
|
|
35
|
+
backdrop-filter: blur(14px);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.toolbar[hidden] {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.title {
|
|
43
|
+
flex: 1 1 240px;
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
font-weight: 700;
|
|
46
|
+
color: #334155;
|
|
47
|
+
min-width: 0;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
text-overflow: ellipsis;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.toolbar-group {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 8px;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.toolbar button {
|
|
61
|
+
appearance: none;
|
|
62
|
+
border: 1px solid #cbd5e1;
|
|
63
|
+
background: #ffffff;
|
|
64
|
+
color: #0f172a;
|
|
65
|
+
border-radius: 999px;
|
|
66
|
+
min-width: 36px;
|
|
67
|
+
height: 36px;
|
|
68
|
+
padding: 0 12px;
|
|
69
|
+
font: inherit;
|
|
70
|
+
font-weight: 700;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
transition:
|
|
73
|
+
transform 140ms ease,
|
|
74
|
+
background-color 180ms ease,
|
|
75
|
+
border-color 180ms ease,
|
|
76
|
+
box-shadow 180ms ease;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.toolbar button:hover:not(:disabled) {
|
|
80
|
+
transform: translateY(-1px);
|
|
81
|
+
box-shadow: 0 10px 18px rgba(15, 23, 42, 0.08);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.toolbar button:active:not(:disabled) {
|
|
85
|
+
transform: translateY(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.toolbar button:disabled {
|
|
89
|
+
opacity: 0.45;
|
|
90
|
+
cursor: not-allowed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.toolbar button.primary {
|
|
94
|
+
background: #0f766e;
|
|
95
|
+
border-color: #0f766e;
|
|
96
|
+
color: #f8fafc;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.toolbar .value {
|
|
100
|
+
min-width: 68px;
|
|
101
|
+
text-align: center;
|
|
102
|
+
font-size: 13px;
|
|
103
|
+
color: #475569;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.stage {
|
|
107
|
+
position: relative;
|
|
108
|
+
min-height: 320px;
|
|
109
|
+
max-height: 80vh;
|
|
110
|
+
overflow: auto;
|
|
111
|
+
scroll-behavior: smooth;
|
|
112
|
+
overscroll-behavior: contain;
|
|
113
|
+
background:
|
|
114
|
+
radial-gradient(circle at top, rgba(15, 118, 110, 0.08), transparent 22%),
|
|
115
|
+
#eef2f7;
|
|
116
|
+
padding: 16px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.stage.single {
|
|
120
|
+
display: grid;
|
|
121
|
+
place-items: center;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.page-stack {
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
gap: 16px;
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.page {
|
|
132
|
+
background: #ffffff;
|
|
133
|
+
border-radius: 8px;
|
|
134
|
+
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.12);
|
|
135
|
+
opacity: 1;
|
|
136
|
+
transform: translateY(0) scale(1);
|
|
137
|
+
transition:
|
|
138
|
+
opacity 220ms ease,
|
|
139
|
+
transform 220ms ease,
|
|
140
|
+
box-shadow 220ms ease;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.page.entering {
|
|
144
|
+
opacity: 0;
|
|
145
|
+
transform: translateY(16px) scale(0.985);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
canvas {
|
|
149
|
+
display: block;
|
|
150
|
+
max-width: 100%;
|
|
151
|
+
height: auto;
|
|
152
|
+
border-radius: 8px;
|
|
153
|
+
transition: filter 180ms ease;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.status {
|
|
157
|
+
position: absolute;
|
|
158
|
+
inset: 16px;
|
|
159
|
+
display: none;
|
|
160
|
+
align-items: center;
|
|
161
|
+
justify-content: center;
|
|
162
|
+
padding: 24px;
|
|
163
|
+
border-radius: 12px;
|
|
164
|
+
background: rgba(248, 250, 252, 0.92);
|
|
165
|
+
color: #475569;
|
|
166
|
+
text-align: center;
|
|
167
|
+
font-size: 14px;
|
|
168
|
+
line-height: 1.5;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.status.visible {
|
|
172
|
+
display: flex;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@media (max-width: 720px) {
|
|
176
|
+
.toolbar {
|
|
177
|
+
align-items: stretch;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.title {
|
|
181
|
+
flex-basis: 100%;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.toolbar-group {
|
|
185
|
+
width: 100%;
|
|
186
|
+
justify-content: flex-start;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.toolbar button {
|
|
190
|
+
min-height: 40px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.stage {
|
|
194
|
+
max-height: none;
|
|
195
|
+
min-height: 60vh;
|
|
196
|
+
padding: 12px;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@media (prefers-reduced-motion: reduce) {
|
|
201
|
+
.toolbar button,
|
|
202
|
+
.page,
|
|
203
|
+
canvas {
|
|
204
|
+
transition: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.stage {
|
|
208
|
+
scroll-behavior: auto;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
`;
|
|
212
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkN5B,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type GenusPdfViewerFit = "width" | "page" | "none";
|
|
2
|
+
export type GenusPdfViewerSource = string | URL | Uint8Array | Blob;
|
|
3
|
+
export interface GenusPdfViewerConfig {
|
|
4
|
+
src: GenusPdfViewerSource;
|
|
5
|
+
title?: string;
|
|
6
|
+
page?: number;
|
|
7
|
+
zoom?: number;
|
|
8
|
+
minZoom?: number;
|
|
9
|
+
maxZoom?: number;
|
|
10
|
+
zoomStep?: number;
|
|
11
|
+
fit?: GenusPdfViewerFit;
|
|
12
|
+
continuous?: boolean;
|
|
13
|
+
showToolbar?: boolean;
|
|
14
|
+
allowDownload?: boolean;
|
|
15
|
+
workerSrc?: string;
|
|
16
|
+
withCredentials?: boolean;
|
|
17
|
+
httpHeaders?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface GenusPdfViewerReadyEventDetail {
|
|
20
|
+
page: number;
|
|
21
|
+
pageCount: number;
|
|
22
|
+
zoom: number;
|
|
23
|
+
}
|
|
24
|
+
export interface GenusPdfViewerPageChangeEventDetail {
|
|
25
|
+
page: number;
|
|
26
|
+
pageCount: number;
|
|
27
|
+
}
|
|
28
|
+
export interface GenusPdfViewerZoomChangeEventDetail {
|
|
29
|
+
zoom: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GenusPdfViewerErrorEventDetail {
|
|
32
|
+
error: unknown;
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
export interface GenusPdfViewerEventMap {
|
|
36
|
+
ready: GenusPdfViewerReadyEventDetail;
|
|
37
|
+
pagechange: GenusPdfViewerPageChangeEventDetail;
|
|
38
|
+
zoomchange: GenusPdfViewerZoomChangeEventDetail;
|
|
39
|
+
error: GenusPdfViewerErrorEventDetail;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1D,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mCAAmC;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mCAAmC;IAClD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,8BAA8B,CAAC;IACtC,UAAU,EAAE,mCAAmC,CAAC;IAChD,UAAU,EAAE,mCAAmC,CAAC;IAChD,KAAK,EAAE,8BAA8B,CAAC;CACvC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/viewer.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { GenusPdfViewerConfig } from "./types.js";
|
|
2
|
+
export declare class GenusPdfViewerElement extends HTMLElement {
|
|
3
|
+
#private;
|
|
4
|
+
static get observedAttributes(): string[];
|
|
5
|
+
constructor();
|
|
6
|
+
connectedCallback(): void;
|
|
7
|
+
disconnectedCallback(): void;
|
|
8
|
+
attributeChangedCallback(): void;
|
|
9
|
+
configure(config: GenusPdfViewerConfig): void;
|
|
10
|
+
reload(): Promise<void>;
|
|
11
|
+
goToPage(page: number): Promise<void>;
|
|
12
|
+
nextPage(): Promise<void>;
|
|
13
|
+
prevPage(): Promise<void>;
|
|
14
|
+
setZoom(zoom: number): Promise<void>;
|
|
15
|
+
zoomIn(): Promise<void>;
|
|
16
|
+
zoomOut(): Promise<void>;
|
|
17
|
+
download(): Promise<void>;
|
|
18
|
+
destroy(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
declare global {
|
|
21
|
+
interface HTMLElementTagNameMap {
|
|
22
|
+
"genus-pdf-viewer": GenusPdfViewerElement;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare function defineGenusPdfViewerElement(tagName?: string): void;
|
|
26
|
+
export declare function createGenusPdfViewer(container: HTMLElement, config: GenusPdfViewerConfig): GenusPdfViewerElement;
|
|
27
|
+
//# sourceMappingURL=viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../src/viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EAMrB,MAAM,YAAY,CAAC;AA+MpB,qBAAa,qBAAsB,SAAQ,WAAW;;IACpD,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;;IAmID,iBAAiB,IAAI,IAAI;IAkBzB,oBAAoB,IAAI,IAAI;IAK5B,wBAAwB,IAAI,IAAI;IAOhC,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IA+DvC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBrC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAWxB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAkV/B;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,qBAAqB,CAAC;KAC3C;CACF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,SAAuB,GAAG,IAAI,CAIhF;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,oBAAoB,GAC3B,qBAAqB,CAMvB"}
|