@apollo-design/react-docx-preview 0.1.0
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 +201 -0
- package/dist/DocxViewer.d.ts +20 -0
- package/dist/components/DocumentStage.d.ts +2 -0
- package/dist/components/ErrorBanner.d.ts +2 -0
- package/dist/components/ThumbnailsSidebar.d.ts +2 -0
- package/dist/components/Toolbar.d.ts +2 -0
- package/dist/components/icons/IconChevronDown.d.ts +2 -0
- package/dist/components/icons/IconDownload.d.ts +2 -0
- package/dist/components/icons/IconNextPage.d.ts +2 -0
- package/dist/components/icons/IconOpenFile.d.ts +2 -0
- package/dist/components/icons/IconPrevPage.d.ts +2 -0
- package/dist/components/icons/IconThumbs.d.ts +2 -0
- package/dist/components/icons/IconZoomIn.d.ts +2 -0
- package/dist/components/icons/IconZoomOut.d.ts +2 -0
- package/dist/context.d.ts +34 -0
- package/dist/hooks/useDocViewer.d.ts +50 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +684 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +2 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright (c) 2016-2023 Volodymyr Baydalka
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { Options } from '@apollo-design/docx-preview';
|
|
3
|
+
export interface DocxViewerProps {
|
|
4
|
+
/** document data — Blob / ArrayBuffer / Uint8Array; re-renders on change */
|
|
5
|
+
data?: Blob | ArrayBuffer | Uint8Array | null;
|
|
6
|
+
/** document name for the download button */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** 'fit' | number (0.75, 75, …) — initial zoom; mount-time only */
|
|
9
|
+
initialScale?: 'fit' | number;
|
|
10
|
+
/** initial thumbnail sidebar visibility; mount-time only */
|
|
11
|
+
showThumbs?: boolean;
|
|
12
|
+
/** library render options, merged over { paginate, experimental } */
|
|
13
|
+
renderOptions?: Partial<Options>;
|
|
14
|
+
className?: string;
|
|
15
|
+
style?: CSSProperties;
|
|
16
|
+
onRendered?: (result: unknown) => void;
|
|
17
|
+
onError?: (error: unknown) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function DocxViewer({ data, name, initialScale, showThumbs, renderOptions, className, style, onRendered, onError, }: DocxViewerProps): import("react").JSX.Element;
|
|
20
|
+
export default DocxViewer;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DocxViewerApi } from './hooks/useDocViewer';
|
|
2
|
+
export declare const DocxViewerContext: import('react').Context<{
|
|
3
|
+
loading: boolean;
|
|
4
|
+
error: {
|
|
5
|
+
title: string;
|
|
6
|
+
detail: string;
|
|
7
|
+
};
|
|
8
|
+
docLoaded: boolean;
|
|
9
|
+
currentPage: number;
|
|
10
|
+
pageCount: number;
|
|
11
|
+
currentScale: number;
|
|
12
|
+
scaleMode: number | "fit";
|
|
13
|
+
thumbsVisible: boolean;
|
|
14
|
+
dropdownOpen: boolean;
|
|
15
|
+
setDropdownOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>;
|
|
16
|
+
pagerShown: boolean;
|
|
17
|
+
thumbsShown: boolean;
|
|
18
|
+
canPrev: boolean;
|
|
19
|
+
canNext: boolean;
|
|
20
|
+
canZoomOut: boolean;
|
|
21
|
+
canZoomIn: boolean;
|
|
22
|
+
scaleLabel: string;
|
|
23
|
+
open: (data: ArrayBuffer | Uint8Array | Blob, name?: string) => Promise<void>;
|
|
24
|
+
goToPage: (index: number) => void;
|
|
25
|
+
jumpToPage: (inputValue: string) => void;
|
|
26
|
+
zoomStep: (direction: 1 | -1) => void;
|
|
27
|
+
setScale: (value: string) => void;
|
|
28
|
+
toggleThumbs: () => void;
|
|
29
|
+
download: () => void;
|
|
30
|
+
stage: import('react').RefObject<HTMLElement>;
|
|
31
|
+
docBox: import('react').RefObject<HTMLElement>;
|
|
32
|
+
thumbs: import('react').RefObject<HTMLElement>;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function useDocxViewer(): DocxViewerApi;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { Options } from '@apollo-design/docx-preview';
|
|
3
|
+
export interface DocxViewerRefs {
|
|
4
|
+
stage: RefObject<HTMLElement | null>;
|
|
5
|
+
docBox: RefObject<HTMLElement | null>;
|
|
6
|
+
thumbs: RefObject<HTMLElement | null>;
|
|
7
|
+
}
|
|
8
|
+
export interface DocxViewerOptions {
|
|
9
|
+
/** 'fit' (fit-width, never upscales) or a number like 0.75 / 75 */
|
|
10
|
+
initialScale?: 'fit' | number;
|
|
11
|
+
/** initial thumbnail sidebar visibility (default true) */
|
|
12
|
+
showThumbs?: boolean;
|
|
13
|
+
/** library render options, merged over { hideWrapperOnPrint, paginate, experimental } */
|
|
14
|
+
renderOptions?: Partial<Options>;
|
|
15
|
+
onRendered?: (result: unknown) => void;
|
|
16
|
+
onError?: (error: unknown) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function useDocViewer(refs: DocxViewerRefs, options?: DocxViewerOptions): {
|
|
19
|
+
loading: boolean;
|
|
20
|
+
error: {
|
|
21
|
+
title: string;
|
|
22
|
+
detail: string;
|
|
23
|
+
};
|
|
24
|
+
docLoaded: boolean;
|
|
25
|
+
currentPage: number;
|
|
26
|
+
pageCount: number;
|
|
27
|
+
currentScale: number;
|
|
28
|
+
scaleMode: number | "fit";
|
|
29
|
+
thumbsVisible: boolean;
|
|
30
|
+
dropdownOpen: boolean;
|
|
31
|
+
setDropdownOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>;
|
|
32
|
+
pagerShown: boolean;
|
|
33
|
+
thumbsShown: boolean;
|
|
34
|
+
canPrev: boolean;
|
|
35
|
+
canNext: boolean;
|
|
36
|
+
canZoomOut: boolean;
|
|
37
|
+
canZoomIn: boolean;
|
|
38
|
+
scaleLabel: string;
|
|
39
|
+
open: (data: Blob | ArrayBuffer | Uint8Array | null | undefined, name?: string) => Promise<void>;
|
|
40
|
+
goToPage: (index: number) => void;
|
|
41
|
+
jumpToPage: (inputValue: string) => void;
|
|
42
|
+
zoomStep: (direction: 1 | -1) => void;
|
|
43
|
+
setScale: (value: string) => void;
|
|
44
|
+
toggleThumbs: () => void;
|
|
45
|
+
download: () => void;
|
|
46
|
+
stage: RefObject<HTMLElement>;
|
|
47
|
+
docBox: RefObject<HTMLElement>;
|
|
48
|
+
thumbs: RefObject<HTMLElement>;
|
|
49
|
+
};
|
|
50
|
+
export type DocxViewerApi = ReturnType<typeof useDocViewer>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DocxViewer, DocxViewer as DocxPreview, default } from './DocxViewer';
|
|
2
|
+
export type { DocxViewerProps } from './DocxViewer';
|
|
3
|
+
export { useDocViewer } from './hooks/useDocViewer';
|
|
4
|
+
export type { DocxViewerApi, DocxViewerOptions, DocxViewerRefs } from './hooks/useDocViewer';
|
|
5
|
+
export { renderAsync, parseAsync, renderDocument, defaultOptions } from '@apollo-design/docx-preview';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import { createContext as e, useContext as t, useEffect as n, useRef as r, useState as i } from "react";
|
|
2
|
+
import { defaultOptions as a, parseAsync as o, renderAsync as s, renderAsync as c, renderDocument as l } from "@apollo-design/docx-preview";
|
|
3
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
4
|
+
//#region src/hooks/useDocViewer.ts
|
|
5
|
+
var f = .1, p = 4, m = .25, h = 1, g = [
|
|
6
|
+
"tl",
|
|
7
|
+
"tr",
|
|
8
|
+
"bl",
|
|
9
|
+
"br"
|
|
10
|
+
];
|
|
11
|
+
function _(e) {
|
|
12
|
+
if (!e || e.byteLength < 4) return !1;
|
|
13
|
+
let t = new Uint8Array(e, 0, 4);
|
|
14
|
+
return t[0] === 208 && t[1] === 207 && t[2] === 17 && t[3] === 224;
|
|
15
|
+
}
|
|
16
|
+
function v(e) {
|
|
17
|
+
return e && typeof e == "object" && "message" in e ? String(e.message) : String(e);
|
|
18
|
+
}
|
|
19
|
+
function y(e) {
|
|
20
|
+
if (typeof e == "number" && isFinite(e) && e > 0) {
|
|
21
|
+
let t = e > 10 ? e / 100 : e;
|
|
22
|
+
return Math.max(f, Math.min(p, Math.round(t * 100) / 100));
|
|
23
|
+
}
|
|
24
|
+
return "fit";
|
|
25
|
+
}
|
|
26
|
+
function b(e, t = {}) {
|
|
27
|
+
let [a, o] = i(!1), [s, l] = i(null), [u, d] = i(!1), [b, x] = i(0), [S, C] = i(0), [w, T] = i(1), [E, D] = i(() => y(t.initialScale)), [O, k] = i(t.showThumbs !== !1), [A, j] = i(!1), M = r({
|
|
28
|
+
docName: "",
|
|
29
|
+
docBlob: null,
|
|
30
|
+
wrapperEl: null,
|
|
31
|
+
sections: [],
|
|
32
|
+
naturalWidth: 0,
|
|
33
|
+
naturalHeight: 0,
|
|
34
|
+
currentPage: 0,
|
|
35
|
+
pageObserver: null,
|
|
36
|
+
thumbPageSynced: -1
|
|
37
|
+
}), N = r({
|
|
38
|
+
docLoaded: u,
|
|
39
|
+
currentPage: b,
|
|
40
|
+
scaleMode: E,
|
|
41
|
+
thumbsVisible: O,
|
|
42
|
+
currentScale: w
|
|
43
|
+
});
|
|
44
|
+
N.current = {
|
|
45
|
+
docLoaded: u,
|
|
46
|
+
currentPage: b,
|
|
47
|
+
scaleMode: E,
|
|
48
|
+
thumbsVisible: O,
|
|
49
|
+
currentScale: w
|
|
50
|
+
};
|
|
51
|
+
let P = r(t);
|
|
52
|
+
P.current = t;
|
|
53
|
+
let F = S > 1, I = O && S > 1 && u, L = u && b > 0, ee = u && b < S - 1, te = u && w > .100001, R = u && w < 3.999999, z = E === "fit" ? "适应宽度" : Math.round(E * 100) + "%";
|
|
54
|
+
function B() {
|
|
55
|
+
let t = e.thumbs.current;
|
|
56
|
+
if (!t) return;
|
|
57
|
+
let n = t.children, r = M.current.currentPage;
|
|
58
|
+
for (let e = 0; e < n.length; e++) n[e].classList.toggle("current", Number(n[e].getAttribute("data-page")) === r);
|
|
59
|
+
N.current.thumbsVisible && n.length > 1 && N.current.docLoaded && M.current.thumbPageSynced !== r && n[r] && (M.current.thumbPageSynced = r, n[r].scrollIntoView({ block: "nearest" }));
|
|
60
|
+
}
|
|
61
|
+
function V() {
|
|
62
|
+
let t = e.thumbs.current;
|
|
63
|
+
if (!t) return;
|
|
64
|
+
t.innerHTML = "", M.current.thumbPageSynced = -1;
|
|
65
|
+
let n = M.current.sections;
|
|
66
|
+
if (n.length <= 1 || !M.current.naturalWidth) return;
|
|
67
|
+
let r = 94 / M.current.naturalWidth;
|
|
68
|
+
for (let e = 0; e < n.length; e++) {
|
|
69
|
+
let i = document.createElement("div");
|
|
70
|
+
i.className = "thumb", i.setAttribute("data-page", String(e));
|
|
71
|
+
let a = document.createElement("div");
|
|
72
|
+
a.className = "thumb-page", a.style.height = Math.ceil(n[e].offsetHeight * r) + "px";
|
|
73
|
+
let o = n[e].cloneNode(!0);
|
|
74
|
+
o.removeAttribute("data-page"), o.style.transform = "scale(" + r + ")", o.style.transformOrigin = "top left", a.appendChild(o);
|
|
75
|
+
let s = document.createElement("div");
|
|
76
|
+
s.className = "thumb-label", s.textContent = String(e + 1), i.appendChild(a), i.appendChild(s), t.appendChild(i);
|
|
77
|
+
}
|
|
78
|
+
B();
|
|
79
|
+
}
|
|
80
|
+
function H() {
|
|
81
|
+
let t = e.stage.current;
|
|
82
|
+
if (!M.current.naturalWidth || !t) return 1;
|
|
83
|
+
let n = t.clientWidth - 48;
|
|
84
|
+
return Math.min(h, n / M.current.naturalWidth);
|
|
85
|
+
}
|
|
86
|
+
function U() {
|
|
87
|
+
let t = e.stage.current, n = e.docBox.current, r = M.current.wrapperEl, i = M.current.naturalWidth;
|
|
88
|
+
if (!N.current.docLoaded || !r || !i || !t || !n) return;
|
|
89
|
+
let a = t.scrollHeight - t.clientHeight, o = t.scrollWidth - t.clientWidth, s = a > 0 ? t.scrollTop / a : 0, c = o > 0 ? t.scrollLeft / o : 0, l = N.current.scaleMode, u = l === "fit" ? H() : l;
|
|
90
|
+
T(u), n.style.width = Math.ceil(i * u) + "px", n.style.height = Math.ceil(M.current.naturalHeight * u) + "px", r.style.width = i + "px", r.style.transform = "scale(" + u + ")", r.style.transformOrigin = "top left";
|
|
91
|
+
let d = t.scrollHeight - t.clientHeight, f = t.scrollWidth - t.clientWidth;
|
|
92
|
+
d > 0 && (t.scrollTop = s * d), f > 0 && (t.scrollLeft = c * f);
|
|
93
|
+
}
|
|
94
|
+
function W(e) {
|
|
95
|
+
let t = N.current.currentScale / m, n = Math.round(t);
|
|
96
|
+
Math.abs(t - n) < .01 && (t = n);
|
|
97
|
+
let r = e > 0 ? (Math.floor(t) + 1) * m : (Math.ceil(t) - 1) * m;
|
|
98
|
+
G(Math.max(f, Math.min(p, Math.round(r * 100) / 100)));
|
|
99
|
+
}
|
|
100
|
+
function G(e) {
|
|
101
|
+
N.current.scaleMode = e, D(e), U();
|
|
102
|
+
}
|
|
103
|
+
function K(e) {
|
|
104
|
+
j(!1), G(e === "fit" ? "fit" : parseFloat(e));
|
|
105
|
+
}
|
|
106
|
+
function q() {
|
|
107
|
+
let e = !N.current.thumbsVisible;
|
|
108
|
+
k(e), N.current.thumbsVisible = e, N.current.docLoaded && N.current.scaleMode === "fit" && U();
|
|
109
|
+
}
|
|
110
|
+
function J(e) {
|
|
111
|
+
let t = getComputedStyle(e), n = parseFloat(t.paddingTop) || 0, r = parseFloat(t.paddingRight) || 0, i = parseFloat(t.paddingBottom) || 0, a = parseFloat(t.paddingLeft) || 0, o = e.offsetWidth - r, s = e.offsetHeight - i, c = Math.max(4, Math.round(Math.min(n, r, i, a) * .25)), l = {
|
|
112
|
+
tl: {
|
|
113
|
+
left: a - c,
|
|
114
|
+
top: n - c
|
|
115
|
+
},
|
|
116
|
+
tr: {
|
|
117
|
+
left: o,
|
|
118
|
+
top: n - c
|
|
119
|
+
},
|
|
120
|
+
bl: {
|
|
121
|
+
left: a - c,
|
|
122
|
+
top: s
|
|
123
|
+
},
|
|
124
|
+
br: {
|
|
125
|
+
left: o,
|
|
126
|
+
top: s
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
for (let t of g) {
|
|
130
|
+
let n = document.createElement("i");
|
|
131
|
+
n.className = "page-corner " + t, n.setAttribute("aria-hidden", "true"), n.style.width = c + "px", n.style.height = c + "px", n.style.left = l[t].left + "px", n.style.top = l[t].top + "px", e.appendChild(n);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function Y(t) {
|
|
135
|
+
let n = e.stage.current;
|
|
136
|
+
if (!n) return;
|
|
137
|
+
let r = parseFloat(getComputedStyle(n).paddingTop) || 0;
|
|
138
|
+
n.scrollTop = n.scrollTop + (t.getBoundingClientRect().top - n.getBoundingClientRect().top) - r;
|
|
139
|
+
}
|
|
140
|
+
function X(e) {
|
|
141
|
+
let t = M.current.sections;
|
|
142
|
+
if (!N.current.docLoaded || t.length === 0) return;
|
|
143
|
+
let n = Math.max(0, Math.min(e, t.length - 1));
|
|
144
|
+
M.current.currentPage = n, x(n), Y(t[n]);
|
|
145
|
+
}
|
|
146
|
+
function Z(e) {
|
|
147
|
+
let t = parseInt(e, 10);
|
|
148
|
+
Number.isNaN(t) || X(t - 1);
|
|
149
|
+
}
|
|
150
|
+
function ne() {
|
|
151
|
+
M.current.pageObserver && (M.current.pageObserver.disconnect(), M.current.pageObserver = null);
|
|
152
|
+
let t = e.stage.current, n = M.current.sections;
|
|
153
|
+
if (typeof window.IntersectionObserver != "function" || n.length <= 1 || !t) return;
|
|
154
|
+
let r = [];
|
|
155
|
+
M.current.pageObserver = new IntersectionObserver((e) => {
|
|
156
|
+
for (let t of e) {
|
|
157
|
+
let e = Number(t.target.getAttribute("data-page"));
|
|
158
|
+
Number.isNaN(e) || (r[e] = t.intersectionRatio);
|
|
159
|
+
}
|
|
160
|
+
let t = -1, n = -1;
|
|
161
|
+
for (let e = 0; e < r.length; e++) r[e] > n && (n = r[e], t = e);
|
|
162
|
+
t >= 0 && n > 0 && (M.current.currentPage = t, x(t));
|
|
163
|
+
}, {
|
|
164
|
+
root: t,
|
|
165
|
+
threshold: [
|
|
166
|
+
0,
|
|
167
|
+
.25,
|
|
168
|
+
.5,
|
|
169
|
+
.75,
|
|
170
|
+
1
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
for (let e of n) M.current.pageObserver.observe(e);
|
|
174
|
+
}
|
|
175
|
+
function Q() {
|
|
176
|
+
M.current.pageObserver && (M.current.pageObserver.disconnect(), M.current.pageObserver = null);
|
|
177
|
+
let t = e.docBox.current, n = e.thumbs.current;
|
|
178
|
+
t && (t.innerHTML = "", t.style.width = "", t.style.height = ""), n && (n.innerHTML = ""), M.current.thumbPageSynced = -1, M.current.wrapperEl = null, M.current.sections = [], M.current.naturalWidth = 0, M.current.naturalHeight = 0, M.current.currentPage = 0, x(0), C(0), d(!1);
|
|
179
|
+
}
|
|
180
|
+
async function $(t, n) {
|
|
181
|
+
if (Q(), l(null), j(!1), o(!0), _(t)) {
|
|
182
|
+
o(!1);
|
|
183
|
+
let e = /* @__PURE__ */ Error("legacy binary document (.wps/.doc), not OOXML");
|
|
184
|
+
l({
|
|
185
|
+
title: "无法打开" + (n ? "「" + n + "」" : "文档"),
|
|
186
|
+
detail: "这是旧版二进制文档格式(.wps / .doc),不是 OOXML(.docx)。即使是新版 WPS Office,默认保存的 .wps 仍是二进制格式。请用 WPS 或 Word 将其另存为 .docx 后重试。"
|
|
187
|
+
}), P.current.onError?.(e);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
let r = {
|
|
191
|
+
hideWrapperOnPrint: !0,
|
|
192
|
+
paginate: !0,
|
|
193
|
+
experimental: !0,
|
|
194
|
+
...P.current.renderOptions
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
let n = e.docBox.current, i = e.stage.current;
|
|
198
|
+
if (!n || !i) throw Error("viewer is not mounted");
|
|
199
|
+
let a = await c(t, n, void 0, r), o = n.querySelector(".docx-wrapper") || n;
|
|
200
|
+
M.current.wrapperEl = o;
|
|
201
|
+
let s = o.querySelectorAll("section"), l = [];
|
|
202
|
+
for (let e = 0; e < s.length; e++) {
|
|
203
|
+
let t = s[e];
|
|
204
|
+
t.setAttribute("data-page", String(e)), J(t), l.push(t);
|
|
205
|
+
}
|
|
206
|
+
M.current.sections = l;
|
|
207
|
+
let u = 0;
|
|
208
|
+
for (let e of l) u = Math.max(u, e.offsetWidth);
|
|
209
|
+
u || (u = o.scrollWidth), M.current.naturalWidth = u, M.current.naturalHeight = o.offsetHeight, M.current.currentPage = 0, N.current.docLoaded = !0, d(!0), C(l.length), x(0), U(), V(), ne(), i.scrollTop = 0, i.scrollLeft = 0, P.current.onRendered?.(a);
|
|
210
|
+
} catch (e) {
|
|
211
|
+
console.error(e), Q(), l({
|
|
212
|
+
title: "无法打开" + (n ? "「" + n + "」" : "文档"),
|
|
213
|
+
detail: v(e) + " —— 请确认这是有效且未加密的 .docx 文件。"
|
|
214
|
+
}), P.current.onError?.(e);
|
|
215
|
+
} finally {
|
|
216
|
+
o(!1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function re(e, t) {
|
|
220
|
+
if (!e) return;
|
|
221
|
+
let n = t || typeof File < "u" && e instanceof File && e.name || "document.docx";
|
|
222
|
+
if (M.current.docName = n, M.current.docBlob = e instanceof Blob ? e : new Blob([e]), e instanceof Blob) {
|
|
223
|
+
let t;
|
|
224
|
+
try {
|
|
225
|
+
t = await new Promise((t, n) => {
|
|
226
|
+
let r = new FileReader();
|
|
227
|
+
r.onload = () => t(r.result), r.onerror = () => n(r.error || /* @__PURE__ */ Error("FileReader failed")), r.readAsArrayBuffer(e);
|
|
228
|
+
});
|
|
229
|
+
} catch (e) {
|
|
230
|
+
l({
|
|
231
|
+
title: "读取文件失败",
|
|
232
|
+
detail: "浏览器无法读取「" + n + "」,请重试。"
|
|
233
|
+
}), P.current.onError?.(e);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
return $(t, n);
|
|
237
|
+
}
|
|
238
|
+
return $(e, n);
|
|
239
|
+
}
|
|
240
|
+
function ie() {
|
|
241
|
+
let e = M.current.docBlob;
|
|
242
|
+
if (!e) return;
|
|
243
|
+
let t = URL.createObjectURL(e), n = document.createElement("a");
|
|
244
|
+
n.href = t, n.download = M.current.docName || "document.docx", document.body.appendChild(n), n.click(), document.body.removeChild(n), setTimeout(() => URL.revokeObjectURL(t), 1e4);
|
|
245
|
+
}
|
|
246
|
+
return n(() => {
|
|
247
|
+
function t() {
|
|
248
|
+
N.current.docLoaded && N.current.scaleMode === "fit" && U();
|
|
249
|
+
}
|
|
250
|
+
function n(e) {
|
|
251
|
+
e.target.closest(".docx-viewer .scale-select") || j(!1);
|
|
252
|
+
}
|
|
253
|
+
function r(t) {
|
|
254
|
+
t.key === "Escape" && j(!1);
|
|
255
|
+
let n = t.target && t.target.tagName;
|
|
256
|
+
n !== "INPUT" && n !== "TEXTAREA" && n !== "SELECT" && (!e.stage.current || !e.stage.current.contains(t.target) || (t.key === "ArrowLeft" || t.key === "ArrowUp" || t.key === "PageUp" ? (t.preventDefault(), X(N.current.currentPage - 1)) : t.key === "ArrowRight" || t.key === "ArrowDown" || t.key === "PageDown" || t.key === " " ? (t.preventDefault(), X(N.current.currentPage + 1)) : t.key === "Home" ? X(0) : t.key === "End" && X(M.current.sections.length - 1)));
|
|
257
|
+
}
|
|
258
|
+
return window.addEventListener("resize", t), document.addEventListener("click", n), document.addEventListener("keydown", r), () => {
|
|
259
|
+
window.removeEventListener("resize", t), document.removeEventListener("click", n), document.removeEventListener("keydown", r), M.current.pageObserver && (M.current.pageObserver.disconnect(), M.current.pageObserver = null);
|
|
260
|
+
};
|
|
261
|
+
}, []), n(() => {
|
|
262
|
+
B();
|
|
263
|
+
}, [b, I]), {
|
|
264
|
+
...e,
|
|
265
|
+
loading: a,
|
|
266
|
+
error: s,
|
|
267
|
+
docLoaded: u,
|
|
268
|
+
currentPage: b,
|
|
269
|
+
pageCount: S,
|
|
270
|
+
currentScale: w,
|
|
271
|
+
scaleMode: E,
|
|
272
|
+
thumbsVisible: O,
|
|
273
|
+
dropdownOpen: A,
|
|
274
|
+
setDropdownOpen: j,
|
|
275
|
+
pagerShown: F,
|
|
276
|
+
thumbsShown: I,
|
|
277
|
+
canPrev: L,
|
|
278
|
+
canNext: ee,
|
|
279
|
+
canZoomOut: te,
|
|
280
|
+
canZoomIn: R,
|
|
281
|
+
scaleLabel: z,
|
|
282
|
+
open: re,
|
|
283
|
+
goToPage: X,
|
|
284
|
+
jumpToPage: Z,
|
|
285
|
+
zoomStep: W,
|
|
286
|
+
setScale: K,
|
|
287
|
+
toggleThumbs: q,
|
|
288
|
+
download: ie
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region src/context.ts
|
|
293
|
+
var x = e(null);
|
|
294
|
+
function S() {
|
|
295
|
+
let e = t(x);
|
|
296
|
+
if (!e) throw Error("DocxViewer components must be used inside <DocxViewer>");
|
|
297
|
+
return e;
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/components/icons/IconThumbs.tsx
|
|
301
|
+
function C() {
|
|
302
|
+
return /* @__PURE__ */ u("svg", {
|
|
303
|
+
width: "16",
|
|
304
|
+
height: "16",
|
|
305
|
+
fill: "none",
|
|
306
|
+
viewBox: "0 0 24 24",
|
|
307
|
+
"aria-hidden": "true",
|
|
308
|
+
children: /* @__PURE__ */ u("path", {
|
|
309
|
+
fill: "currentColor",
|
|
310
|
+
fillRule: "evenodd",
|
|
311
|
+
d: "M21 5H11v14h10zM3 5h6v14H3zm0-2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm2 4.25a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5zm-.75 3.5A.75.75 0 0 1 5 10h2a.75.75 0 0 1 0 1.5H5a.75.75 0 0 1-.75-.75m.75 2a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5z",
|
|
312
|
+
clipRule: "evenodd"
|
|
313
|
+
})
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/components/icons/IconPrevPage.tsx
|
|
318
|
+
function w() {
|
|
319
|
+
return /* @__PURE__ */ u("svg", {
|
|
320
|
+
width: "16",
|
|
321
|
+
height: "16",
|
|
322
|
+
viewBox: "0 0 16 16",
|
|
323
|
+
fill: "none",
|
|
324
|
+
"aria-hidden": "true",
|
|
325
|
+
children: /* @__PURE__ */ u("path", {
|
|
326
|
+
d: "M3 10l5-5 5 5",
|
|
327
|
+
stroke: "currentColor",
|
|
328
|
+
strokeWidth: "1.5",
|
|
329
|
+
strokeLinecap: "round",
|
|
330
|
+
strokeLinejoin: "round"
|
|
331
|
+
})
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/components/icons/IconNextPage.tsx
|
|
336
|
+
function T() {
|
|
337
|
+
return /* @__PURE__ */ u("svg", {
|
|
338
|
+
width: "16",
|
|
339
|
+
height: "16",
|
|
340
|
+
viewBox: "0 0 16 16",
|
|
341
|
+
fill: "none",
|
|
342
|
+
"aria-hidden": "true",
|
|
343
|
+
children: /* @__PURE__ */ u("path", {
|
|
344
|
+
d: "M3 6l5 5 5-5",
|
|
345
|
+
stroke: "currentColor",
|
|
346
|
+
strokeWidth: "1.5",
|
|
347
|
+
strokeLinecap: "round",
|
|
348
|
+
strokeLinejoin: "round"
|
|
349
|
+
})
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/components/icons/IconZoomOut.tsx
|
|
354
|
+
function E() {
|
|
355
|
+
return /* @__PURE__ */ d("svg", {
|
|
356
|
+
width: "16",
|
|
357
|
+
height: "16",
|
|
358
|
+
viewBox: "0 0 16 16",
|
|
359
|
+
fill: "none",
|
|
360
|
+
"aria-hidden": "true",
|
|
361
|
+
children: [/* @__PURE__ */ u("circle", {
|
|
362
|
+
cx: "7",
|
|
363
|
+
cy: "7",
|
|
364
|
+
r: "4.5",
|
|
365
|
+
stroke: "currentColor",
|
|
366
|
+
strokeWidth: "1.5"
|
|
367
|
+
}), /* @__PURE__ */ u("path", {
|
|
368
|
+
d: "M4.8 7h4.4M10.2 10.2L14 14",
|
|
369
|
+
stroke: "currentColor",
|
|
370
|
+
strokeWidth: "1.5",
|
|
371
|
+
strokeLinecap: "round",
|
|
372
|
+
strokeLinejoin: "round"
|
|
373
|
+
})]
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/components/icons/IconZoomIn.tsx
|
|
378
|
+
function D() {
|
|
379
|
+
return /* @__PURE__ */ d("svg", {
|
|
380
|
+
width: "16",
|
|
381
|
+
height: "16",
|
|
382
|
+
viewBox: "0 0 16 16",
|
|
383
|
+
fill: "none",
|
|
384
|
+
"aria-hidden": "true",
|
|
385
|
+
children: [/* @__PURE__ */ u("circle", {
|
|
386
|
+
cx: "7",
|
|
387
|
+
cy: "7",
|
|
388
|
+
r: "4.5",
|
|
389
|
+
stroke: "currentColor",
|
|
390
|
+
strokeWidth: "1.5"
|
|
391
|
+
}), /* @__PURE__ */ u("path", {
|
|
392
|
+
d: "M4.8 7h4.4M7 4.8v4.4M10.2 10.2L14 14",
|
|
393
|
+
stroke: "currentColor",
|
|
394
|
+
strokeWidth: "1.5",
|
|
395
|
+
strokeLinecap: "round",
|
|
396
|
+
strokeLinejoin: "round"
|
|
397
|
+
})]
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
//#endregion
|
|
401
|
+
//#region src/components/icons/IconChevronDown.tsx
|
|
402
|
+
function O() {
|
|
403
|
+
return /* @__PURE__ */ u("svg", {
|
|
404
|
+
width: "10",
|
|
405
|
+
height: "10",
|
|
406
|
+
viewBox: "0 0 10 10",
|
|
407
|
+
fill: "none",
|
|
408
|
+
"aria-hidden": "true",
|
|
409
|
+
children: /* @__PURE__ */ u("path", {
|
|
410
|
+
d: "M2 3.5l3 3 3-3",
|
|
411
|
+
stroke: "currentColor",
|
|
412
|
+
strokeWidth: "1.5",
|
|
413
|
+
strokeLinecap: "round",
|
|
414
|
+
strokeLinejoin: "round"
|
|
415
|
+
})
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/components/icons/IconOpenFile.tsx
|
|
420
|
+
function k() {
|
|
421
|
+
return /* @__PURE__ */ u("svg", {
|
|
422
|
+
width: "16",
|
|
423
|
+
height: "16",
|
|
424
|
+
viewBox: "0 0 16 16",
|
|
425
|
+
fill: "none",
|
|
426
|
+
"aria-hidden": "true",
|
|
427
|
+
children: /* @__PURE__ */ u("path", {
|
|
428
|
+
d: "M2 5.2A1.7 1.7 0 0 1 3.7 3.5h2.5l1.5 1.7h4.6a1.7 1.7 0 0 1 1.7 1.7v4.4a1.7 1.7 0 0 1-1.7 1.7H3.7A1.7 1.7 0 0 1 2 11.3V5.2Z",
|
|
429
|
+
stroke: "currentColor",
|
|
430
|
+
strokeWidth: "1.5",
|
|
431
|
+
strokeLinejoin: "round"
|
|
432
|
+
})
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/components/icons/IconDownload.tsx
|
|
437
|
+
function A() {
|
|
438
|
+
return /* @__PURE__ */ u("svg", {
|
|
439
|
+
width: "16",
|
|
440
|
+
height: "16",
|
|
441
|
+
viewBox: "0 0 16 16",
|
|
442
|
+
fill: "none",
|
|
443
|
+
"aria-hidden": "true",
|
|
444
|
+
children: /* @__PURE__ */ u("path", {
|
|
445
|
+
d: "M8 2.5V10M8 10L4.8 6.8 8 10l3.2-3.2M2.5 13.5h11",
|
|
446
|
+
stroke: "currentColor",
|
|
447
|
+
strokeWidth: "1.5",
|
|
448
|
+
strokeLinecap: "round",
|
|
449
|
+
strokeLinejoin: "round"
|
|
450
|
+
})
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
//#endregion
|
|
454
|
+
//#region src/components/Toolbar.tsx
|
|
455
|
+
var j = [
|
|
456
|
+
"fit",
|
|
457
|
+
"0.5",
|
|
458
|
+
"0.75",
|
|
459
|
+
"1",
|
|
460
|
+
"1.25",
|
|
461
|
+
"1.5",
|
|
462
|
+
"2"
|
|
463
|
+
];
|
|
464
|
+
function M() {
|
|
465
|
+
let e = S(), t = r(null);
|
|
466
|
+
function n(t) {
|
|
467
|
+
let n = t.currentTarget;
|
|
468
|
+
e.jumpToPage(n.value), n.blur();
|
|
469
|
+
}
|
|
470
|
+
function i(t) {
|
|
471
|
+
let n = t.currentTarget, r = n.files && n.files[0];
|
|
472
|
+
r && e.open(r), n.value = "";
|
|
473
|
+
}
|
|
474
|
+
return /* @__PURE__ */ d("header", {
|
|
475
|
+
className: "toolbar",
|
|
476
|
+
hidden: !e.docLoaded,
|
|
477
|
+
children: [
|
|
478
|
+
/* @__PURE__ */ d("div", {
|
|
479
|
+
className: "toolbar-left",
|
|
480
|
+
children: [
|
|
481
|
+
/* @__PURE__ */ u("button", {
|
|
482
|
+
className: e.thumbsShown ? "tbtn active" : "tbtn",
|
|
483
|
+
type: "button",
|
|
484
|
+
title: "缩略图",
|
|
485
|
+
disabled: !e.docLoaded || e.pageCount <= 1,
|
|
486
|
+
onClick: e.toggleThumbs,
|
|
487
|
+
children: /* @__PURE__ */ u(C, {})
|
|
488
|
+
}),
|
|
489
|
+
/* @__PURE__ */ u("span", { className: "toolbar-divider" }),
|
|
490
|
+
/* @__PURE__ */ d("span", {
|
|
491
|
+
className: "pager",
|
|
492
|
+
hidden: !e.pagerShown,
|
|
493
|
+
children: [
|
|
494
|
+
/* @__PURE__ */ u("button", {
|
|
495
|
+
className: "tbtn",
|
|
496
|
+
type: "button",
|
|
497
|
+
title: "上一页",
|
|
498
|
+
disabled: !e.canPrev,
|
|
499
|
+
onClick: () => e.goToPage(e.currentPage - 1),
|
|
500
|
+
children: /* @__PURE__ */ u(w, {})
|
|
501
|
+
}),
|
|
502
|
+
/* @__PURE__ */ d("span", {
|
|
503
|
+
className: "page-info",
|
|
504
|
+
children: [/* @__PURE__ */ u("input", {
|
|
505
|
+
className: "page-input",
|
|
506
|
+
type: "number",
|
|
507
|
+
min: 1,
|
|
508
|
+
step: 1,
|
|
509
|
+
defaultValue: e.pageCount > 0 ? e.currentPage + 1 : "",
|
|
510
|
+
"aria-label": "当前页码",
|
|
511
|
+
onKeyDown: (e) => {
|
|
512
|
+
e.key === "Enter" && n(e);
|
|
513
|
+
},
|
|
514
|
+
onBlur: n
|
|
515
|
+
}, e.currentPage), /* @__PURE__ */ d("span", {
|
|
516
|
+
className: "page-total",
|
|
517
|
+
children: ["/ ", e.pageCount > 0 ? e.pageCount : "–"]
|
|
518
|
+
})]
|
|
519
|
+
}),
|
|
520
|
+
/* @__PURE__ */ u("button", {
|
|
521
|
+
className: "tbtn",
|
|
522
|
+
type: "button",
|
|
523
|
+
title: "下一页",
|
|
524
|
+
disabled: !e.canNext,
|
|
525
|
+
onClick: () => e.goToPage(e.currentPage + 1),
|
|
526
|
+
children: /* @__PURE__ */ u(T, {})
|
|
527
|
+
})
|
|
528
|
+
]
|
|
529
|
+
})
|
|
530
|
+
]
|
|
531
|
+
}),
|
|
532
|
+
/* @__PURE__ */ u("div", {
|
|
533
|
+
className: "toolbar-center",
|
|
534
|
+
children: /* @__PURE__ */ d("div", {
|
|
535
|
+
className: "zoom-group",
|
|
536
|
+
children: [
|
|
537
|
+
/* @__PURE__ */ u("button", {
|
|
538
|
+
className: "tbtn",
|
|
539
|
+
type: "button",
|
|
540
|
+
title: "缩小",
|
|
541
|
+
disabled: !e.canZoomOut,
|
|
542
|
+
onClick: () => e.zoomStep(-1),
|
|
543
|
+
children: /* @__PURE__ */ u(E, {})
|
|
544
|
+
}),
|
|
545
|
+
/* @__PURE__ */ d("div", {
|
|
546
|
+
className: "scale-select",
|
|
547
|
+
children: [/* @__PURE__ */ d("button", {
|
|
548
|
+
className: "tbtn scale-display",
|
|
549
|
+
type: "button",
|
|
550
|
+
onClick: (t) => {
|
|
551
|
+
t.stopPropagation(), e.setDropdownOpen(!e.dropdownOpen);
|
|
552
|
+
},
|
|
553
|
+
children: [/* @__PURE__ */ u("span", { children: e.scaleLabel }), /* @__PURE__ */ u(O, {})]
|
|
554
|
+
}), /* @__PURE__ */ u("div", {
|
|
555
|
+
className: "dropdown",
|
|
556
|
+
hidden: !e.dropdownOpen,
|
|
557
|
+
children: j.map((t) => /* @__PURE__ */ u("button", {
|
|
558
|
+
type: "button",
|
|
559
|
+
className: e.scaleMode === "fit" && t === "fit" || String(e.scaleMode) === t ? "selected" : void 0,
|
|
560
|
+
onClick: () => e.setScale(t),
|
|
561
|
+
children: t === "fit" ? "适应宽度" : Math.round(parseFloat(t) * 100) + "%"
|
|
562
|
+
}, t))
|
|
563
|
+
})]
|
|
564
|
+
}),
|
|
565
|
+
/* @__PURE__ */ u("button", {
|
|
566
|
+
className: "tbtn",
|
|
567
|
+
type: "button",
|
|
568
|
+
title: "放大",
|
|
569
|
+
disabled: !e.canZoomIn,
|
|
570
|
+
onClick: () => e.zoomStep(1),
|
|
571
|
+
children: /* @__PURE__ */ u(D, {})
|
|
572
|
+
})
|
|
573
|
+
]
|
|
574
|
+
})
|
|
575
|
+
}),
|
|
576
|
+
/* @__PURE__ */ d("div", {
|
|
577
|
+
className: "toolbar-right",
|
|
578
|
+
children: [
|
|
579
|
+
/* @__PURE__ */ u("button", {
|
|
580
|
+
className: "tbtn",
|
|
581
|
+
type: "button",
|
|
582
|
+
title: "打开文档",
|
|
583
|
+
onClick: () => t.current?.click(),
|
|
584
|
+
children: /* @__PURE__ */ u(k, {})
|
|
585
|
+
}),
|
|
586
|
+
/* @__PURE__ */ u("button", {
|
|
587
|
+
className: "tbtn",
|
|
588
|
+
type: "button",
|
|
589
|
+
title: "下载文档",
|
|
590
|
+
disabled: !e.docLoaded,
|
|
591
|
+
onClick: e.download,
|
|
592
|
+
children: /* @__PURE__ */ u(A, {})
|
|
593
|
+
}),
|
|
594
|
+
/* @__PURE__ */ u("input", {
|
|
595
|
+
ref: t,
|
|
596
|
+
type: "file",
|
|
597
|
+
accept: ".docx",
|
|
598
|
+
hidden: !0,
|
|
599
|
+
onChange: i
|
|
600
|
+
})
|
|
601
|
+
]
|
|
602
|
+
})
|
|
603
|
+
]
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
//#endregion
|
|
607
|
+
//#region src/components/ErrorBanner.tsx
|
|
608
|
+
function N() {
|
|
609
|
+
let e = S();
|
|
610
|
+
return /* @__PURE__ */ d("div", {
|
|
611
|
+
className: "error-banner",
|
|
612
|
+
hidden: !e.error,
|
|
613
|
+
children: [/* @__PURE__ */ u("strong", { children: e.error?.title }), /* @__PURE__ */ u("span", { children: e.error?.detail })]
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/components/ThumbnailsSidebar.tsx
|
|
618
|
+
function P() {
|
|
619
|
+
let e = S();
|
|
620
|
+
function t(t) {
|
|
621
|
+
let n = t.target.closest(".thumb");
|
|
622
|
+
n && e.goToPage(Number(n.getAttribute("data-page")));
|
|
623
|
+
}
|
|
624
|
+
return /* @__PURE__ */ u("aside", {
|
|
625
|
+
ref: e.thumbs,
|
|
626
|
+
className: "thumbs",
|
|
627
|
+
hidden: !e.thumbsShown,
|
|
628
|
+
"aria-label": "页面缩略图",
|
|
629
|
+
onClick: t
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
//#endregion
|
|
633
|
+
//#region src/components/DocumentStage.tsx
|
|
634
|
+
function F() {
|
|
635
|
+
let e = S();
|
|
636
|
+
return /* @__PURE__ */ d("main", {
|
|
637
|
+
ref: e.stage,
|
|
638
|
+
className: "stage",
|
|
639
|
+
children: [/* @__PURE__ */ d("div", {
|
|
640
|
+
className: "loading",
|
|
641
|
+
hidden: !e.loading,
|
|
642
|
+
children: [/* @__PURE__ */ u("div", { className: "spinner" }), /* @__PURE__ */ u("p", { children: "加载中…" })]
|
|
643
|
+
}), /* @__PURE__ */ u("div", {
|
|
644
|
+
ref: e.docBox,
|
|
645
|
+
className: "document"
|
|
646
|
+
})]
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
//#endregion
|
|
650
|
+
//#region src/DocxViewer.tsx
|
|
651
|
+
function I({ data: e, name: t, initialScale: i, showThumbs: a, renderOptions: o, className: s, style: c, onRendered: l, onError: f }) {
|
|
652
|
+
let p = b({
|
|
653
|
+
stage: r(null),
|
|
654
|
+
docBox: r(null),
|
|
655
|
+
thumbs: r(null)
|
|
656
|
+
}, {
|
|
657
|
+
initialScale: i,
|
|
658
|
+
showThumbs: a,
|
|
659
|
+
renderOptions: o,
|
|
660
|
+
onRendered: l,
|
|
661
|
+
onError: f
|
|
662
|
+
});
|
|
663
|
+
return n(() => {
|
|
664
|
+
e && p.open(e, t);
|
|
665
|
+
}, [e, t]), /* @__PURE__ */ u(x.Provider, {
|
|
666
|
+
value: p,
|
|
667
|
+
children: /* @__PURE__ */ d("div", {
|
|
668
|
+
className: s ? `docx-viewer ${s}` : "docx-viewer",
|
|
669
|
+
style: c,
|
|
670
|
+
children: [
|
|
671
|
+
/* @__PURE__ */ u(M, {}),
|
|
672
|
+
/* @__PURE__ */ u(N, {}),
|
|
673
|
+
/* @__PURE__ */ d("div", {
|
|
674
|
+
className: "body",
|
|
675
|
+
children: [/* @__PURE__ */ u(P, {}), /* @__PURE__ */ u(F, {})]
|
|
676
|
+
})
|
|
677
|
+
]
|
|
678
|
+
})
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
//#endregion
|
|
682
|
+
export { I as DocxPreview, I as DocxViewer, I as default, a as defaultOptions, o as parseAsync, s as renderAsync, l as renderDocument, b as useDocViewer };
|
|
683
|
+
|
|
684
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/hooks/useDocViewer.ts","../src/context.ts","../src/components/icons/IconThumbs.tsx","../src/components/icons/IconPrevPage.tsx","../src/components/icons/IconNextPage.tsx","../src/components/icons/IconZoomOut.tsx","../src/components/icons/IconZoomIn.tsx","../src/components/icons/IconChevronDown.tsx","../src/components/icons/IconOpenFile.tsx","../src/components/icons/IconDownload.tsx","../src/components/Toolbar.tsx","../src/components/ErrorBanner.tsx","../src/components/ThumbnailsSidebar.tsx","../src/components/DocumentStage.tsx","../src/DocxViewer.tsx"],"sourcesContent":["// Core viewer logic, ported from apps/viewer/viewer.js. UI-facing values are\n// React state; everything else (library render output, thumbnail clones, page\n// corners, zoom transforms) is imperative DOM work against element refs.\n// A ref mirror (stateRef) lets the once-registered global listeners read\n// fresh values.\nimport { useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport { renderAsync } from '@apollo-design/docx-preview';\nimport type { Options } from '@apollo-design/docx-preview';\n\n// Zoom-button range. Stepping clamps here so a step never strands the\n// buttons in a disabled state.\nconst SCALE_MIN = 0.1;\nconst SCALE_MAX = 4;\nconst SCALE_STEP = 0.25;\n// Fit-width never upscales: a document reads best at its natural size.\nconst FIT_MAX = 1;\nconst STAGE_PADDING = 24; // .stage padding on each side, see viewer.css\nconst THUMB_WIDTH = 96; // matches .thumb-page width in viewer.css\nconst CORNER_NAMES = ['tl', 'tr', 'bl', 'br'] as const;\n\nexport interface DocxViewerRefs {\n stage: RefObject<HTMLElement | null>;\n docBox: RefObject<HTMLElement | null>;\n thumbs: RefObject<HTMLElement | null>;\n}\n\nexport interface DocxViewerOptions {\n /** 'fit' (fit-width, never upscales) or a number like 0.75 / 75 */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility (default true) */\n showThumbs?: boolean;\n /** library render options, merged over { hideWrapperOnPrint, paginate, experimental } */\n renderOptions?: Partial<Options>;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\n// OLE2 compound-file magic (D0 CF 11 E0 ...): legacy binary documents —\n// old .doc, and .wps as still saved by default even by recent WPS Office.\nfunction isLegacyBinary(buffer: ArrayBuffer): boolean {\n if (!buffer || buffer.byteLength < 4) return false;\n const b = new Uint8Array(buffer, 0, 4);\n return b[0] === 0xd0 && b[1] === 0xcf && b[2] === 0x11 && b[3] === 0xe0;\n}\n\nfunction errorText(err: unknown): string {\n if (err && typeof err === 'object' && 'message' in err) return String((err as Error).message);\n return String(err);\n}\n\nfunction initialScaleMode(value: 'fit' | number | undefined): 'fit' | number {\n if (typeof value === 'number' && isFinite(value) && value > 0) {\n const n = value > 10 ? value / 100 : value;\n return Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(n * 100) / 100));\n }\n return 'fit';\n}\n\nexport function useDocViewer(refs: DocxViewerRefs, options: DocxViewerOptions = {}) {\n // ── UI state ───────────────────────────────────────────────────────────\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<{ title: string; detail: string } | null>(null);\n const [docLoaded, setDocLoaded] = useState(false);\n const [currentPage, setCurrentPage] = useState(0);\n const [pageCount, setPageCount] = useState(0);\n const [currentScale, setCurrentScale] = useState(1);\n const [scaleMode, setScaleMode] = useState<'fit' | number>(() => initialScaleMode(options.initialScale));\n const [thumbsVisible, setThumbsVisible] = useState(options.showThumbs !== false);\n const [dropdownOpen, setDropdownOpen] = useState(false);\n\n // ── Mutable internals (live DOM produced by the library) ───────────────\n const it = useRef({\n docName: '',\n // The opened document kept as a Blob so the download button works\n // regardless of the input type (Blob / ArrayBuffer / Uint8Array).\n docBlob: null as Blob | null,\n wrapperEl: null as HTMLElement | null,\n sections: [] as HTMLElement[],\n naturalWidth: 0,\n naturalHeight: 0,\n currentPage: 0, // authoritative copy (state mirrors it for rendering)\n pageObserver: null as IntersectionObserver | null,\n thumbPageSynced: -1,\n });\n // Latest-value mirror for the once-registered global listeners.\n const stateRef = useRef({ docLoaded, currentPage, scaleMode, thumbsVisible, currentScale });\n stateRef.current = { docLoaded, currentPage, scaleMode, thumbsVisible, currentScale };\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const pagerShown = pageCount > 1;\n const thumbsShown = thumbsVisible && pageCount > 1 && docLoaded;\n const canPrev = docLoaded && currentPage > 0;\n const canNext = docLoaded && currentPage < pageCount - 1;\n const canZoomOut = docLoaded && currentScale > SCALE_MIN + 1e-6;\n const canZoomIn = docLoaded && currentScale < SCALE_MAX - 1e-6;\n const scaleLabel = scaleMode === 'fit' ? '适应宽度' : Math.round(scaleMode * 100) + '%';\n\n // ── Thumbnails ─────────────────────────────────────────────────────────\n // Deep clones of page sections shrunk with a CSS transform — no re-render.\n\n function syncThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n const items = box.children;\n const page = it.current.currentPage;\n for (let i = 0; i < items.length; i++) {\n items[i].classList.toggle('current', Number(items[i].getAttribute('data-page')) === page);\n }\n const shown = stateRef.current.thumbsVisible && items.length > 1 && stateRef.current.docLoaded;\n if (shown && it.current.thumbPageSynced !== page && items[page]) {\n it.current.thumbPageSynced = page;\n (items[page] as HTMLElement).scrollIntoView({ block: 'nearest' });\n }\n }\n\n function buildThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n box.innerHTML = '';\n it.current.thumbPageSynced = -1;\n const sections = it.current.sections;\n if (sections.length <= 1 || !it.current.naturalWidth) return;\n\n const scale = (THUMB_WIDTH - 2) / it.current.naturalWidth; // 2px = .thumb-page borders\n for (let i = 0; i < sections.length; i++) {\n const item = document.createElement('div');\n item.className = 'thumb';\n item.setAttribute('data-page', String(i));\n\n const page = document.createElement('div');\n page.className = 'thumb-page';\n page.style.height = Math.ceil(sections[i].offsetHeight * scale) + 'px';\n\n const clone = sections[i].cloneNode(true) as HTMLElement;\n clone.removeAttribute('data-page');\n clone.style.transform = 'scale(' + scale + ')';\n clone.style.transformOrigin = 'top left';\n page.appendChild(clone);\n\n const label = document.createElement('div');\n label.className = 'thumb-label';\n label.textContent = String(i + 1);\n\n item.appendChild(page);\n item.appendChild(label);\n box.appendChild(item);\n }\n syncThumbs();\n }\n\n // ── Zoom ───────────────────────────────────────────────────────────────\n // Zoom is pure CSS: the library renders once at natural size, and we scale\n // .docx-wrapper with a transform inside an explicitly-sized box.\n\n function fitScale() {\n const stage = refs.stage.current;\n if (!it.current.naturalWidth || !stage) return 1;\n const avail = stage.clientWidth - STAGE_PADDING * 2;\n return Math.min(FIT_MAX, avail / it.current.naturalWidth);\n }\n\n function applyScale() {\n const stage = refs.stage.current;\n const docBox = refs.docBox.current;\n const wrapperEl = it.current.wrapperEl;\n const naturalWidth = it.current.naturalWidth;\n if (!stateRef.current.docLoaded || !wrapperEl || !naturalWidth || !stage || !docBox) return;\n\n // Keep the same relative scroll position across the zoom change.\n const maxY = stage.scrollHeight - stage.clientHeight;\n const maxX = stage.scrollWidth - stage.clientWidth;\n const ratioY = maxY > 0 ? stage.scrollTop / maxY : 0;\n const ratioX = maxX > 0 ? stage.scrollLeft / maxX : 0;\n\n const mode = stateRef.current.scaleMode;\n const scale = mode === 'fit' ? fitScale() : mode;\n setCurrentScale(scale);\n docBox.style.width = Math.ceil(naturalWidth * scale) + 'px';\n docBox.style.height = Math.ceil(it.current.naturalHeight * scale) + 'px';\n // Pin the wrapper to the natural content width so the top-left-origin\n // transform lines up exactly with the zoom box.\n wrapperEl.style.width = naturalWidth + 'px';\n wrapperEl.style.transform = 'scale(' + scale + ')';\n wrapperEl.style.transformOrigin = 'top left';\n\n const newMaxY = stage.scrollHeight - stage.clientHeight;\n const newMaxX = stage.scrollWidth - stage.clientWidth;\n if (newMaxY > 0) stage.scrollTop = ratioY * newMaxY;\n if (newMaxX > 0) stage.scrollLeft = ratioX * newMaxX;\n }\n\n function zoomStep(direction: 1 | -1) {\n // currentScale carries sub-pixel fit error (e.g. 0.99998); snap to the\n // nearest grid line within tolerance first, or the buttons look dead.\n let steps = stateRef.current.currentScale / SCALE_STEP;\n const nearest = Math.round(steps);\n if (Math.abs(steps - nearest) < 0.01) steps = nearest;\n const next = direction > 0 ? (Math.floor(steps) + 1) * SCALE_STEP : (Math.ceil(steps) - 1) * SCALE_STEP;\n applyScaleWith(Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(next * 100) / 100)));\n }\n\n // applyScale reads scaleMode from stateRef; callers that just changed the\n // mode must update the mirror first (setScaleMode alone lands next render).\n function applyScaleWith(mode: 'fit' | number) {\n stateRef.current.scaleMode = mode;\n setScaleMode(mode);\n applyScale();\n }\n\n function setScale(value: string) {\n setDropdownOpen(false);\n applyScaleWith(value === 'fit' ? 'fit' : parseFloat(value));\n }\n\n function toggleThumbs() {\n const next = !stateRef.current.thumbsVisible;\n setThumbsVisible(next);\n stateRef.current.thumbsVisible = next;\n // The sidebar eats stage width — re-fit so fit-width stays correct.\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n\n // ── Page corners ───────────────────────────────────────────────────────\n // Office/WPS-style crop marks: four L-brackets whose joints sit exactly\n // on the text-area corners (the page's padding corners).\n\n function addPageCorners(section: HTMLElement) {\n const cs = getComputedStyle(section);\n const padTop = parseFloat(cs.paddingTop) || 0;\n const padRight = parseFloat(cs.paddingRight) || 0;\n const padBottom = parseFloat(cs.paddingBottom) || 0;\n const padLeft = parseFloat(cs.paddingLeft) || 0;\n const right = section.offsetWidth - padRight; // text-area right edge\n const bottom = section.offsetHeight - padBottom; // text-area bottom edge\n const size = Math.max(4, Math.round(Math.min(padTop, padRight, padBottom, padLeft) * 0.25));\n\n const boxes = {\n tl: { left: padLeft - size, top: padTop - size },\n tr: { left: right, top: padTop - size },\n bl: { left: padLeft - size, top: bottom },\n br: { left: right, top: bottom },\n };\n\n for (const name of CORNER_NAMES) {\n const corner = document.createElement('i');\n corner.className = 'page-corner ' + name;\n corner.setAttribute('aria-hidden', 'true');\n corner.style.width = size + 'px';\n corner.style.height = size + 'px';\n corner.style.left = boxes[name].left + 'px';\n corner.style.top = boxes[name].top + 'px';\n section.appendChild(corner);\n }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────\n\n function scrollStageTo(element: HTMLElement) {\n const stage = refs.stage.current;\n if (!stage) return;\n const paddingTop = parseFloat(getComputedStyle(stage).paddingTop) || 0;\n stage.scrollTop =\n stage.scrollTop +\n (element.getBoundingClientRect().top - stage.getBoundingClientRect().top) -\n paddingTop;\n }\n\n function goToPage(index: number) {\n const sections = it.current.sections;\n if (!stateRef.current.docLoaded || sections.length === 0) return;\n const clamped = Math.max(0, Math.min(index, sections.length - 1));\n it.current.currentPage = clamped;\n setCurrentPage(clamped);\n scrollStageTo(sections[clamped]);\n }\n\n function jumpToPage(inputValue: string) {\n const target = parseInt(inputValue, 10);\n if (!Number.isNaN(target)) goToPage(target - 1);\n }\n\n function trackPages() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const stage = refs.stage.current;\n const sections = it.current.sections;\n if (typeof window.IntersectionObserver !== 'function' || sections.length <= 1 || !stage) return;\n\n const ratios: number[] = [];\n it.current.pageObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const index = Number((entry.target as HTMLElement).getAttribute('data-page'));\n if (!Number.isNaN(index)) ratios[index] = entry.intersectionRatio;\n }\n let bestIndex = -1;\n let bestRatio = -1;\n for (let j = 0; j < ratios.length; j++) {\n if (ratios[j] > bestRatio) {\n bestRatio = ratios[j];\n bestIndex = j;\n }\n }\n if (bestIndex >= 0 && bestRatio > 0) {\n it.current.currentPage = bestIndex;\n setCurrentPage(bestIndex);\n }\n },\n { root: stage, threshold: [0, 0.25, 0.5, 0.75, 1.0] },\n );\n for (const section of sections) it.current.pageObserver.observe(section);\n }\n\n // ── Document loading ───────────────────────────────────────────────────\n\n function resetDocument() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const docBox = refs.docBox.current;\n const thumbs = refs.thumbs.current;\n if (docBox) {\n docBox.innerHTML = '';\n docBox.style.width = '';\n docBox.style.height = '';\n }\n if (thumbs) thumbs.innerHTML = '';\n it.current.thumbPageSynced = -1;\n it.current.wrapperEl = null;\n it.current.sections = [];\n it.current.naturalWidth = 0;\n it.current.naturalHeight = 0;\n it.current.currentPage = 0;\n setCurrentPage(0);\n setPageCount(0);\n setDocLoaded(false);\n }\n\n async function openBuffer(buffer: ArrayBuffer, label: string) {\n resetDocument();\n setError(null);\n setDropdownOpen(false);\n setLoading(true);\n\n if (isLegacyBinary(buffer)) {\n setLoading(false);\n const legacyErr = new Error('legacy binary document (.wps/.doc), not OOXML');\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail:\n '这是旧版二进制文档格式(.wps / .doc),不是 OOXML(.docx)。' +\n '即使是新版 WPS Office,默认保存的 .wps 仍是二进制格式。' +\n '请用 WPS 或 Word 将其另存为 .docx 后重试。',\n });\n optionsRef.current.onError?.(legacyErr);\n return;\n }\n\n const renderOptions: Partial<Options> = {\n hideWrapperOnPrint: true,\n paginate: true,\n // 'experimental' only gates tab-stop computation, which 公文版记\n // lines (right-aligned tab stops) depend on.\n experimental: true,\n ...optionsRef.current.renderOptions,\n };\n\n try {\n const docBox = refs.docBox.current;\n const stage = refs.stage.current;\n if (!docBox || !stage) throw new Error('viewer is not mounted');\n const result = await renderAsync(buffer, docBox, undefined, renderOptions);\n\n const wrapperEl = (docBox.querySelector('.docx-wrapper') as HTMLElement) || docBox;\n it.current.wrapperEl = wrapperEl;\n\n const found = wrapperEl.querySelectorAll('section');\n const sections: HTMLElement[] = [];\n for (let i = 0; i < found.length; i++) {\n const section = found[i] as HTMLElement;\n section.setAttribute('data-page', String(i));\n addPageCorners(section);\n sections.push(section);\n }\n it.current.sections = sections;\n\n // Natural page size, measured before any transform is applied. The\n // wrapper is a full-width block, so its own width is the stage's —\n // the document's real width is the widest fixed-width page section.\n let naturalWidth = 0;\n for (const section of sections) {\n naturalWidth = Math.max(naturalWidth, section.offsetWidth);\n }\n if (!naturalWidth) naturalWidth = wrapperEl.scrollWidth;\n it.current.naturalWidth = naturalWidth;\n it.current.naturalHeight = wrapperEl.offsetHeight;\n it.current.currentPage = 0;\n\n stateRef.current.docLoaded = true;\n setDocLoaded(true);\n setPageCount(sections.length);\n setCurrentPage(0);\n applyScale();\n buildThumbs();\n trackPages();\n stage.scrollTop = 0;\n stage.scrollLeft = 0;\n optionsRef.current.onRendered?.(result);\n } catch (err) {\n console.error(err);\n resetDocument();\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail: errorText(err) + ' —— 请确认这是有效且未加密的 .docx 文件。',\n });\n optionsRef.current.onError?.(err);\n } finally {\n setLoading(false);\n }\n }\n\n /** Opens a document. `data` may be a Blob, ArrayBuffer or Uint8Array. */\n async function open(data: Blob | ArrayBuffer | Uint8Array | null | undefined, name?: string) {\n if (!data) return;\n const docName =\n name || (typeof File !== 'undefined' && data instanceof File && data.name) || 'document.docx';\n it.current.docName = docName;\n it.current.docBlob = data instanceof Blob ? data : new Blob([data as ArrayBuffer]);\n\n if (data instanceof Blob) {\n let buffer: ArrayBuffer;\n try {\n buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error || new Error('FileReader failed'));\n reader.readAsArrayBuffer(data);\n });\n } catch (err) {\n setError({ title: '读取文件失败', detail: '浏览器无法读取「' + docName + '」,请重试。' });\n optionsRef.current.onError?.(err);\n return;\n }\n return openBuffer(buffer, docName);\n }\n return openBuffer(data as ArrayBuffer, docName);\n }\n\n function download() {\n const docBlob = it.current.docBlob;\n if (!docBlob) return;\n const objectUrl = URL.createObjectURL(docBlob);\n const link = document.createElement('a');\n link.href = objectUrl;\n link.download = it.current.docName || 'document.docx';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n setTimeout(() => URL.revokeObjectURL(objectUrl), 10000);\n }\n\n // ── Global listeners (registered once, read fresh state via stateRef) ──\n\n useEffect(() => {\n function onWindowResize() {\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n function onDocumentClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest('.docx-viewer .scale-select')) {\n setDropdownOpen(false);\n }\n }\n function onDocumentKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') setDropdownOpen(false);\n\n const tag = event.target && (event.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n // Only steal navigation keys when this viewer contains the focus.\n if (!refs.stage.current || !refs.stage.current.contains(event.target as Node)) return;\n if (event.key === 'ArrowLeft' || event.key === 'ArrowUp' || event.key === 'PageUp') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage - 1);\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'PageDown' || event.key === ' ') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage + 1);\n } else if (event.key === 'Home') {\n goToPage(0);\n } else if (event.key === 'End') {\n goToPage(it.current.sections.length - 1);\n }\n }\n\n window.addEventListener('resize', onWindowResize);\n document.addEventListener('click', onDocumentClick);\n document.addEventListener('keydown', onDocumentKeydown);\n return () => {\n window.removeEventListener('resize', onWindowResize);\n document.removeEventListener('click', onDocumentClick);\n document.removeEventListener('keydown', onDocumentKeydown);\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // currentPage highlight in the sidebar (the Vue port uses a watcher).\n useEffect(() => {\n syncThumbs();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [currentPage, thumbsShown]);\n\n return {\n // element refs (bound by the components)\n ...refs,\n // state\n loading,\n error,\n docLoaded,\n currentPage,\n pageCount,\n currentScale,\n scaleMode,\n thumbsVisible,\n dropdownOpen,\n setDropdownOpen,\n pagerShown,\n thumbsShown,\n canPrev,\n canNext,\n canZoomOut,\n canZoomIn,\n scaleLabel,\n // actions\n open,\n goToPage,\n jumpToPage,\n zoomStep,\n setScale,\n toggleThumbs,\n download,\n };\n}\n\nexport type DocxViewerApi = ReturnType<typeof useDocViewer>;\n","import { createContext, useContext } from 'react';\nimport type { DocxViewerApi } from './hooks/useDocViewer';\n\nexport const DocxViewerContext = createContext<DocxViewerApi | null>(null);\n\nexport function useDocxViewer(): DocxViewerApi {\n const api = useContext(DocxViewerContext);\n if (!api) throw new Error('DocxViewer components must be used inside <DocxViewer>');\n return api;\n}\n","export function IconThumbs() {\n return (\n <svg width=\"16\" height=\"16\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path fill=\"currentColor\" fillRule=\"evenodd\" d=\"M21 5H11v14h10zM3 5h6v14H3zm0-2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm2 4.25a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5zm-.75 3.5A.75.75 0 0 1 5 10h2a.75.75 0 0 1 0 1.5H5a.75.75 0 0 1-.75-.75m.75 2a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5z\" clipRule=\"evenodd\" />\n </svg>\n );\n}\n","export function IconPrevPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 10l5-5 5 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconNextPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 6l5 5 5-5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomOut() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomIn() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M7 4.8v4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 3.5l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconOpenFile() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 5.2A1.7 1.7 0 0 1 3.7 3.5h2.5l1.5 1.7h4.6a1.7 1.7 0 0 1 1.7 1.7v4.4a1.7 1.7 0 0 1-1.7 1.7H3.7A1.7 1.7 0 0 1 2 11.3V5.2Z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconDownload() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 2.5V10M8 10L4.8 6.8 8 10l3.2-3.2M2.5 13.5h11\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","import { useRef } from 'react';\nimport { useDocxViewer } from '../context';\nimport { IconThumbs } from './icons/IconThumbs';\nimport { IconPrevPage } from './icons/IconPrevPage';\nimport { IconNextPage } from './icons/IconNextPage';\nimport { IconZoomOut } from './icons/IconZoomOut';\nimport { IconZoomIn } from './icons/IconZoomIn';\nimport { IconChevronDown } from './icons/IconChevronDown';\nimport { IconOpenFile } from './icons/IconOpenFile';\nimport { IconDownload } from './icons/IconDownload';\n\nconst SCALES = ['fit', '0.5', '0.75', '1', '1.25', '1.5', '2'];\n\nexport function Toolbar() {\n const api = useDocxViewer();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n function onJump(event: React.SyntheticEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n api.jumpToPage(input.value);\n input.blur();\n }\n\n function onFileChange(event: React.ChangeEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n const file = input.files && input.files[0];\n if (file) api.open(file);\n // Reset so picking the same file twice still fires change.\n input.value = '';\n }\n\n return (\n <header className=\"toolbar\" hidden={!api.docLoaded}>\n <div className=\"toolbar-left\">\n <button\n className={api.thumbsShown ? 'tbtn active' : 'tbtn'}\n type=\"button\"\n title=\"缩略图\"\n disabled={!api.docLoaded || api.pageCount <= 1}\n onClick={api.toggleThumbs}\n >\n <IconThumbs />\n </button>\n <span className=\"toolbar-divider\"></span>\n <span className=\"pager\" hidden={!api.pagerShown}>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"上一页\"\n disabled={!api.canPrev}\n onClick={() => api.goToPage(api.currentPage - 1)}\n >\n <IconPrevPage />\n </button>\n <span className=\"page-info\">\n {/* Uncontrolled + keyed by page: typing is free-form, and a page\n change remounts the input with the fresh page number. */}\n <input\n key={api.currentPage}\n className=\"page-input\"\n type=\"number\"\n min={1}\n step={1}\n defaultValue={api.pageCount > 0 ? api.currentPage + 1 : ''}\n aria-label=\"当前页码\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') onJump(e);\n }}\n onBlur={onJump}\n />\n <span className=\"page-total\">/ {api.pageCount > 0 ? api.pageCount : '–'}</span>\n </span>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"下一页\"\n disabled={!api.canNext}\n onClick={() => api.goToPage(api.currentPage + 1)}\n >\n <IconNextPage />\n </button>\n </span>\n </div>\n\n <div className=\"toolbar-center\">\n <div className=\"zoom-group\">\n <button className=\"tbtn\" type=\"button\" title=\"缩小\" disabled={!api.canZoomOut} onClick={() => api.zoomStep(-1)}>\n <IconZoomOut />\n </button>\n <div className=\"scale-select\">\n <button\n className=\"tbtn scale-display\"\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n api.setDropdownOpen(!api.dropdownOpen);\n }}\n >\n <span>{api.scaleLabel}</span>\n <IconChevronDown />\n </button>\n <div className=\"dropdown\" hidden={!api.dropdownOpen}>\n {SCALES.map((s) => (\n <button\n key={s}\n type=\"button\"\n className={\n (api.scaleMode === 'fit' && s === 'fit') || String(api.scaleMode) === s ? 'selected' : undefined\n }\n onClick={() => api.setScale(s)}\n >\n {s === 'fit' ? '适应宽度' : Math.round(parseFloat(s) * 100) + '%'}\n </button>\n ))}\n </div>\n </div>\n <button className=\"tbtn\" type=\"button\" title=\"放大\" disabled={!api.canZoomIn} onClick={() => api.zoomStep(1)}>\n <IconZoomIn />\n </button>\n </div>\n </div>\n\n <div className=\"toolbar-right\">\n <button className=\"tbtn\" type=\"button\" title=\"打开文档\" onClick={() => fileInputRef.current?.click()}>\n <IconOpenFile />\n </button>\n <button className=\"tbtn\" type=\"button\" title=\"下载文档\" disabled={!api.docLoaded} onClick={api.download}>\n <IconDownload />\n </button>\n <input ref={fileInputRef} type=\"file\" accept=\".docx\" hidden onChange={onFileChange} />\n </div>\n </header>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ErrorBanner() {\n const api = useDocxViewer();\n\n return (\n <div className=\"error-banner\" hidden={!api.error}>\n <strong>{api.error?.title}</strong>\n <span>{api.error?.detail}</span>\n </div>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ThumbnailsSidebar() {\n const api = useDocxViewer();\n\n function onClick(event: React.MouseEvent) {\n const item = (event.target as HTMLElement).closest('.thumb');\n if (item) api.goToPage(Number(item.getAttribute('data-page')));\n }\n\n return (\n <aside\n ref={api.thumbs as React.RefObject<HTMLElement>}\n className=\"thumbs\"\n hidden={!api.thumbsShown}\n aria-label=\"页面缩略图\"\n onClick={onClick}\n />\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function DocumentStage() {\n const api = useDocxViewer();\n\n return (\n <main ref={api.stage as React.RefObject<HTMLElement>} className=\"stage\">\n <div className=\"loading\" hidden={!api.loading}>\n <div className=\"spinner\"></div>\n <p>加载中…</p>\n </div>\n <div ref={api.docBox as React.RefObject<HTMLDivElement>} className=\"document\"></div>\n </main>\n );\n}\n","// React DOCX viewer component — a port of apps/viewer (toolbar, pager,\n// zoom, thumbnails, page corners). The document is fed via the `data` prop\n// and re-renders when it changes; initialScale/showThumbs/renderOptions\n// describe the initial mount (like viewer.html's URL params).\nimport { useEffect, useRef } from 'react';\nimport type { CSSProperties } from 'react';\nimport type { Options } from '@apollo-design/docx-preview';\nimport { useDocViewer } from './hooks/useDocViewer';\nimport { DocxViewerContext } from './context';\nimport { Toolbar } from './components/Toolbar';\nimport { ErrorBanner } from './components/ErrorBanner';\nimport { ThumbnailsSidebar } from './components/ThumbnailsSidebar';\nimport { DocumentStage } from './components/DocumentStage';\nimport './styles/viewer.css';\n\nexport interface DocxViewerProps {\n /** document data — Blob / ArrayBuffer / Uint8Array; re-renders on change */\n data?: Blob | ArrayBuffer | Uint8Array | null;\n /** document name for the download button */\n name?: string;\n /** 'fit' | number (0.75, 75, …) — initial zoom; mount-time only */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility; mount-time only */\n showThumbs?: boolean;\n /** library render options, merged over { paginate, experimental } */\n renderOptions?: Partial<Options>;\n className?: string;\n style?: CSSProperties;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\nexport function DocxViewer({\n data,\n name,\n initialScale,\n showThumbs,\n renderOptions,\n className,\n style,\n onRendered,\n onError,\n}: DocxViewerProps) {\n const stage = useRef<HTMLElement>(null);\n const docBox = useRef<HTMLElement>(null);\n const thumbs = useRef<HTMLElement>(null);\n\n const api = useDocViewer(\n { stage, docBox, thumbs },\n { initialScale, showThumbs, renderOptions, onRendered, onError },\n );\n\n useEffect(() => {\n if (data) api.open(data, name);\n // open is stable (reads latest props through refs); re-run only on data.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data, name]);\n\n return (\n <DocxViewerContext.Provider value={api}>\n <div className={className ? `docx-viewer ${className}` : 'docx-viewer'} style={style}>\n <Toolbar />\n <ErrorBanner />\n <div className=\"body\">\n <ThumbnailsSidebar />\n <DocumentStage />\n </div>\n </div>\n </DocxViewerContext.Provider>\n );\n}\n\nexport default DocxViewer;\n"],"mappings":"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"}
|
package/dist/style.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.docx-viewer{--bg:#f3f4f6;--surface:#fff;--border:#e5e7eb;--text:#1f2329;--text-dim:#6b7280;--accent:#2563eb;--accent-soft:#eff4ff;--error-bg:#fef2f2;--error-border:#fecaca;--error-text:#b91c1c;--font:system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans SC", "Microsoft YaHei", sans-serif}.docx-viewer,.docx-viewer *{box-sizing:border-box;margin:0;padding:0}.docx-viewer{background:var(--bg);height:100%;min-height:240px;font-family:var(--font);color:var(--text);flex-direction:column;font-size:14px;display:flex;overflow:hidden}.docx-viewer .toolbar{z-index:10;background:var(--surface);border-bottom:1px solid var(--border);-webkit-user-select:none;user-select:none;flex:none;align-items:center;padding:6px 12px;display:flex;position:relative}.docx-viewer .toolbar[hidden]{display:none}.docx-viewer .toolbar-divider{background:var(--border);width:1px;height:18px;margin-left:8px;margin-right:8px}.docx-viewer .toolbar-left,.docx-viewer .toolbar-right{flex:1 1 0;align-items:center;display:flex}.docx-viewer .toolbar-right{justify-content:flex-end}.docx-viewer .toolbar-center{align-items:center;display:flex;position:absolute;left:50%;transform:translate(-50%)}.docx-viewer .tbtn{font:inherit;min-width:30px;height:30px;color:var(--text-dim);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0 7px;display:inline-flex}.docx-viewer .tbtn svg{display:block}.docx-viewer .tbtn:hover:not(:disabled){background:var(--bg);color:var(--text)}.docx-viewer .tbtn:disabled{opacity:.35;cursor:default}.docx-viewer .tbtn.active{background:var(--accent-soft);color:var(--accent)}.docx-viewer .pager{align-items:center;display:flex}.docx-viewer .pager[hidden]{display:none}.docx-viewer .page-info{align-items:center;display:flex}.docx-viewer .page-input{font:inherit;text-align:center;width:48px;height:28px;color:var(--text);background:var(--surface);border:1px solid var(--border);-webkit-appearance:textfield;appearance:textfield;-webkit-user-select:text;user-select:text;border-radius:4px;font-size:13px}.docx-viewer .page-input::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.docx-viewer .page-input::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none}.docx-viewer .page-input:focus{border-color:var(--accent);outline:none}.docx-viewer .page-total{color:var(--text-dim);font-variant-numeric:tabular-nums;margin-left:6px;font-size:13px}.docx-viewer .zoom-group{border:1px solid var(--border);background:var(--surface);border-radius:6px;align-items:center;display:flex}.docx-viewer .zoom-group>.tbtn{border-radius:0}.docx-viewer .zoom-group>.tbtn:first-child{border-radius:6px 0 0 6px}.docx-viewer .zoom-group>.tbtn:last-child{border-radius:0 6px 6px 0}.docx-viewer .scale-select{position:relative}.docx-viewer .scale-display{border-left:1px solid var(--border);border-right:1px solid var(--border);min-width:78px;color:var(--text);border-radius:0;font-size:13px}.docx-viewer .scale-display svg{margin-left:4px}.docx-viewer .dropdown{background:var(--surface);border:1px solid var(--border);z-index:30;border-radius:6px;min-width:108px;margin-top:6px;padding:4px;position:absolute;top:100%;left:50%;transform:translate(-50%);box-shadow:0 6px 24px #1018281f}.docx-viewer .dropdown[hidden]{display:none}.docx-viewer .dropdown button{width:100%;font:inherit;text-align:left;color:var(--text);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:6px 10px;font-size:13px;display:block}.docx-viewer .dropdown button:hover{background:var(--bg)}.docx-viewer .dropdown button.selected{color:var(--accent);font-weight:600}.docx-viewer .error-banner{background:var(--error-bg);border-bottom:1px solid var(--error-border);color:var(--error-text);flex:none;padding:10px 14px;font-size:13px;line-height:1.6}.docx-viewer .error-banner[hidden]{display:none}.docx-viewer .error-banner strong{margin-right:10px}.docx-viewer .error-banner span{overflow-wrap:anywhere}.docx-viewer .body{flex:auto;min-height:0;display:flex}.docx-viewer .stage{scrollbar-width:thin;flex:auto;min-width:0;padding:24px;position:relative;overflow:auto}.docx-viewer .document{margin:0 auto;position:relative}.docx-viewer .document .docx-wrapper{background:0 0;min-width:0;padding:0}.docx-viewer .document .docx-wrapper>section.docx{box-shadow:0 1px 3px #1018281a,0 0 1px #10182829}.docx-viewer .page-corner{z-index:2;pointer-events:none;border:0 solid #b9bec7;position:absolute}.docx-viewer .page-corner.tl{border-bottom-width:1.5px;border-right-width:1.5px}.docx-viewer .page-corner.tr{border-bottom-width:1.5px;border-left-width:1.5px}.docx-viewer .page-corner.bl{border-top-width:1.5px;border-right-width:1.5px}.docx-viewer .page-corner.br{border-top-width:1.5px;border-left-width:1.5px}.docx-viewer .thumbs{scrollbar-width:thin;background:var(--bg);border-right:1px solid var(--border);-webkit-user-select:none;user-select:none;flex:none;width:148px;padding:16px 0;overflow:hidden auto}.docx-viewer .thumbs[hidden]{display:none}.docx-viewer .thumb{cursor:pointer;width:104px;margin:0 auto 14px}.docx-viewer .thumb-page{background:var(--surface);border:1px solid var(--border);border-radius:2px;width:96px;margin:0 auto;position:relative;overflow:hidden;box-shadow:0 1px 2px #10182814}.docx-viewer .thumb:hover .thumb-page{border-color:#c7cdd6}.docx-viewer .thumb.current .thumb-page{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}.docx-viewer .thumb-page .docx{pointer-events:none}.docx-viewer .thumbs .docx p:before{content:none!important}.docx-viewer .thumb-label{text-align:center;color:var(--text-dim);font-variant-numeric:tabular-nums;margin-top:5px;font-size:12px}.docx-viewer .thumb.current .thumb-label{color:var(--accent);font-weight:600}@media (max-width:600px){.docx-viewer .thumbs{display:none}}.docx-viewer .loading{color:var(--text-dim);z-index:5;background:#f3f4f6b8;flex-direction:column;justify-content:center;align-items:center;display:flex;position:absolute;top:0;bottom:0;left:0;right:0}.docx-viewer .loading[hidden]{display:none}.docx-viewer .spinner{border:3px solid #2563eb2e;border-top-color:var(--accent);border-radius:50%;width:30px;height:30px;margin-bottom:14px;animation:.9s linear infinite viewer-spin}@keyframes viewer-spin{to{transform:rotate(360deg)}}.docx-viewer .docx span[style*=--docx-font-ea][style*=方正仿宋_GBK]{font-weight:500!important}
|
|
2
|
+
/*$vite$:1*/
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@apollo-design/react-docx-preview",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React DOCX viewer component (toolbar, pager, zoom, thumbnails) built on @apollo-design/docx-preview",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"word",
|
|
7
|
+
"docx",
|
|
8
|
+
"preview",
|
|
9
|
+
"viewer",
|
|
10
|
+
"react"
|
|
11
|
+
],
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"author": "apollocmh",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/apollocmh/docx-preview.git",
|
|
17
|
+
"directory": "packages/react-docx-preview"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://apollocmh.github.io/docx-preview/",
|
|
20
|
+
"bugs": "https://github.com/apollocmh/docx-preview/issues",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./style.css": "./dist/style.css",
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"**/*.css"
|
|
35
|
+
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=17"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@apollo-design/docx-preview": "0.6.3"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public",
|
|
44
|
+
"registry": "https://registry.npmjs.org/"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "vite build"
|
|
48
|
+
}
|
|
49
|
+
}
|