@kne/react-pdf-sign 1.0.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/README.md ADDED
@@ -0,0 +1,346 @@
1
+
2
+ # react-pdf-sign
3
+
4
+
5
+ ### 描述
6
+
7
+ 这是一个功能强大的 React PDF 签名组件库,专为需要在 PDF 文档上添加电子签名的应用场景而设计。该组件库提供了灵活的签名解决方案,支持即时签名添加和预定义签名区域两种模式
8
+
9
+
10
+ ### 安装
11
+
12
+ ```shell
13
+ npm i --save @kne/react-pdf-sign
14
+ ```
15
+
16
+
17
+ ### 概述
18
+
19
+ 这是一个功能强大的 React PDF 签名组件库,专为需要在 PDF 文档上添加电子签名的应用场景而设计。该组件库提供了灵活的签名解决方案,支持即时签名添加和预定义签名区域两种模式。
20
+
21
+ ## 核心特性
22
+
23
+ **直观的签名体验** - 提供手写签名画板,用户可以通过鼠标或触摸设备自然地绘制签名,签名支持实时预览和调整。
24
+
25
+ **灵活的定位控制** - 签名区域可以在 PDF 页面上自由拖拽、缩放和精确定位,支持保持比例缩放,确保签名的视觉效果。
26
+
27
+ **完整的 PDF 操作** - 基于 pdf-lib 和 react-pdf,支持多页 PDF 文档的浏览、签名定位和最终签名文件的生成。
28
+
29
+ **组件化设计** - 提供多个独立组件(PDFSign、PDFViewer、LocationLayer、useSignature),开发者可以根据需求灵活组合使用。
30
+
31
+ **国际化支持** - 内置中英文语言包,支持多语言切换,适合国际化应用。
32
+
33
+ **现代化技术栈** - 基于 React 18+,使用 Konva.js 实现高性能的图形渲染,支持响应式设计。
34
+
35
+ ## 使用场景
36
+
37
+ - 合同签署系统
38
+ - 文档审批流程
39
+ - 电子表单签名
40
+ - 证书颁发系统
41
+ - 法律文件签署
42
+
43
+ 该组件库简化了 PDF 签名的复杂实现,开发者只需要几行代码就能集成完整的签名功能,大大提升了开发效率。
44
+
45
+ ### 示例
46
+
47
+ #### 示例代码
48
+
49
+ - 完整签名流程
50
+ - 演示PDF上传、手写签名创建和签名PDF生成的完整工作流程
51
+ - _ReactPdfSign(@kne/current-lib_react-pdf-sign)[import * as _ReactPdfSign from "@kne/react-pdf-sign"],antd(antd),(@kne/current-lib_react-pdf-sign/dist/index.css)
52
+
53
+ ```jsx
54
+ const { default: ReactPdfSign, useSignature } = _ReactPdfSign;
55
+ const { useState, useRef } = React;
56
+ const { Flex, Button } = antd;
57
+
58
+ const BaseExample = () => {
59
+ const [pdfFile, setPdfFile] = useState(null);
60
+ const [sign, setSign] = useState(null);
61
+ const ref = useRef(null);
62
+ const signatureModal = useSignature();
63
+ return (
64
+ <Flex vertical gap={12}>
65
+ <Flex gap={8}>
66
+ <Button>
67
+ <input
68
+ type="file"
69
+ accept="application/pdf"
70
+ onChange={e => {
71
+ const file = e.target.files[0];
72
+ setPdfFile(URL.createObjectURL(file));
73
+ }}
74
+ />
75
+ </Button>
76
+ <Button
77
+ onClick={() => {
78
+ signatureModal({
79
+ onSuccess: file => {
80
+ setSign(URL.createObjectURL(file));
81
+ }
82
+ });
83
+ }}>
84
+ 添加签名
85
+ </Button>
86
+ {pdfFile && sign && (
87
+ <Button
88
+ onClick={async () => {
89
+ const blob = await ref.current.sign();
90
+ const link = document.createElement('a');
91
+ const url = URL.createObjectURL(blob);
92
+ link.href = url;
93
+ link.download = 'signed-document.pdf';
94
+ link.click();
95
+ URL.revokeObjectURL(url);
96
+ }}>
97
+ 生成签名PDF
98
+ </Button>
99
+ )}
100
+ </Flex>
101
+ {pdfFile ? <ReactPdfSign url={pdfFile} signature={sign} ref={ref} /> : null}
102
+ </Flex>
103
+ );
104
+ };
105
+
106
+ render(<BaseExample />);
107
+
108
+ ```
109
+
110
+ - 签名定位层
111
+ - 展示独立的签名定位组件,支持拖拽和缩放调整签名位置
112
+ - _ReactPdfSign(@kne/current-lib_react-pdf-sign)[import * as _ReactPdfSign from "@kne/react-pdf-sign"],(@kne/current-lib_react-pdf-sign/dist/index.css)
113
+
114
+ ```jsx
115
+ const { LocationLayer } = _ReactPdfSign;
116
+
117
+ const BaseExample = () => {
118
+ return (
119
+ <div>
120
+ <LocationLayer stageWidth={400} stageHeight={300} />
121
+ </div>
122
+ );
123
+ };
124
+
125
+ render(<BaseExample />);
126
+
127
+ ```
128
+
129
+ - PDF查看器
130
+ - 基础的PDF文档查看器,支持页面切换和缩放显示
131
+ - _ReactPdfSign(@kne/current-lib_react-pdf-sign)[import * as _ReactPdfSign from "@kne/react-pdf-sign"],_examplePdf(./doc/example.pdf),(@kne/current-lib_react-pdf-sign/dist/index.css)
132
+
133
+ ```jsx
134
+ const { PDFViewer } = _ReactPdfSign;
135
+ const { default: examplePdf } = _examplePdf;
136
+
137
+ const BaseExample = () => {
138
+ return (
139
+ <div>
140
+ <PDFViewer url={examplePdf} />
141
+ </div>
142
+ );
143
+ };
144
+
145
+ render(<BaseExample />);
146
+
147
+ ```
148
+
149
+ - PDF签名组件
150
+ - 演示PDF签名组件的API使用,包括位置获取、设置和签名文件生成
151
+ - _ReactPdfSign(@kne/current-lib_react-pdf-sign)[import * as _ReactPdfSign from "@kne/react-pdf-sign"],_examplePdf(./doc/example.pdf),_signature(./doc/signature.png),antd(antd),(@kne/current-lib_react-pdf-sign/dist/index.css)
152
+
153
+ ```jsx
154
+ const { PDFSign } = _ReactPdfSign;
155
+ const { default: examplePdf } = _examplePdf;
156
+ const { default: signature } = _signature;
157
+ const { useRef } = React;
158
+ const { Flex, Button, App } = antd;
159
+
160
+ const BaseExample = () => {
161
+ const ref = useRef();
162
+ const ref2 = useRef();
163
+ const { modal } = App.useApp();
164
+ return (
165
+ <Flex vertical gap={24}>
166
+ <Flex vertical gap={8}>
167
+ <Flex gap={8}>
168
+ <Button
169
+ onClick={() => {
170
+ const location = ref.current.getLocation();
171
+ modal.info({
172
+ title: '签名位置',
173
+ content: <pre>{JSON.stringify(location, null, 2)}</pre>
174
+ });
175
+ }}>
176
+ 获取签名位置
177
+ </Button>
178
+ <Button
179
+ onClick={() => {
180
+ ref.current.setLocation({
181
+ size: {
182
+ width: 200,
183
+ height: 50,
184
+ x: 240,
185
+ y: 47
186
+ },
187
+ scaleX: 1,
188
+ scaleY: 1,
189
+ x: 240,
190
+ y: 47
191
+ });
192
+ }}>
193
+ 设置签名位置
194
+ </Button>
195
+ <Button
196
+ onClick={() => {
197
+ const pdfSignature = ref.current.getPdfSignature();
198
+ modal.info({
199
+ title: 'PDF签名信息',
200
+ content: <pre style={{ 'white-space': 'break-spaces' }}>{JSON.stringify(pdfSignature, null, 2)}</pre>
201
+ });
202
+ }}>
203
+ 获取PDF签名信息
204
+ </Button>
205
+ </Flex>
206
+ <PDFSign url={examplePdf} ref={ref} />
207
+ </Flex>
208
+ <Flex vertical gap={8}>
209
+ <div>
210
+ <Button
211
+ onClick={async () => {
212
+ const blob = await ref2.current.sign();
213
+ const link = document.createElement('a');
214
+ const url = URL.createObjectURL(blob);
215
+ link.href = url;
216
+ link.download = 'signed-document.pdf';
217
+ link.click();
218
+ URL.revokeObjectURL(url);
219
+ }}>
220
+ 生成签名文件
221
+ </Button>
222
+ </div>
223
+ <PDFSign url={examplePdf} signature={signature} ref={ref2} />
224
+ </Flex>
225
+ </Flex>
226
+ );
227
+ };
228
+
229
+ render(<BaseExample />);
230
+
231
+ ```
232
+
233
+ - 手写签名画板
234
+ - 展示useSignature Hook的使用,打开手写签名模态框
235
+ - _ReactPdfSign(@kne/current-lib_react-pdf-sign)[import * as _ReactPdfSign from "@kne/react-pdf-sign"],antd(antd),(@kne/current-lib_react-pdf-sign/dist/index.css)
236
+
237
+ ```jsx
238
+ const { useSignature } = _ReactPdfSign;
239
+ const { Button } = antd;
240
+
241
+ const BaseExample = () => {
242
+ const modal = useSignature();
243
+ return (
244
+ <div>
245
+ <Button
246
+ onClick={() => {
247
+ modal({
248
+ onSuccess: file => {
249
+ console.log(file);
250
+ }
251
+ });
252
+ }}>
253
+ 签名
254
+ </Button>
255
+ </div>
256
+ );
257
+ };
258
+
259
+ render(<BaseExample />);
260
+
261
+ ```
262
+
263
+
264
+ ### API
265
+
266
+ ### PDFSign
267
+
268
+ 主要的 PDF 签名组件,集成了 PDF 查看器和签名定位功能。
269
+
270
+ | 属性 | 类型 | 默认值 | 说明 |
271
+ |-------------|--------|-----------|----------------|
272
+ | url | string | - | PDF 文件的 URL 地址 |
273
+ | signature | string | - | 签名图片的 URL 地址 |
274
+ | width | number | 200 | 签名区域的宽度 |
275
+ | height | number | 50 | 签名区域的高度 |
276
+ | padding | number | 8 | 签名区域变换器的内边距 |
277
+ | placeholder | string | '拖拽到签名位置' | 签名区域的占位文本 |
278
+
279
+ #### 实例方法
280
+
281
+ | 方法名 | 参数 | 返回值 | 说明 |
282
+ |-----------------|------------------|---------------|---------------|
283
+ | getLocation | - | object | 获取当前签名位置信息 |
284
+ | setLocation | location: object | - | 设置签名位置 |
285
+ | getPdfSignature | - | object | 获取 PDF 签名信息 |
286
+ | sign | - | Promise<File> | 生成签名后的 PDF 文件 |
287
+
288
+ ### PDFViewer
289
+
290
+ PDF 文档查看器组件,提供 PDF 页面浏览功能。
291
+
292
+ | 属性 | 类型 | 默认值 | 说明 |
293
+ |-------------|--------|------|-------------------|
294
+ | url | string | - | PDF 文件的 URL 地址 |
295
+ | className | string | - | 自定义 CSS 类名 |
296
+ | defaultPage | number | 1 | 默认显示的页码 |
297
+ | maxWidth | number | 1200 | 最大显示宽度 |
298
+ | pdfjsUrl | string | - | 自定义 pdf.js CDN 地址 |
299
+ | apis | object | - | API 配置对象 |
300
+
301
+ #### children 渲染属性
302
+
303
+ 当 children 为函数时,会传入以下参数:
304
+
305
+ | 参数 | 类型 | 说明 |
306
+ |-------------|--------|-----------|
307
+ | size | object | 当前页面的尺寸信息 |
308
+ | currentPage | number | 当前页码 |
309
+ | pageSize | number | 总页数 |
310
+
311
+ ### LocationLayer
312
+
313
+ 签名定位层组件,用于在 PDF 上定位和调整签名区域。
314
+
315
+ | 属性 | 类型 | 默认值 | 说明 |
316
+ |-------------|----------|-----------|----------|
317
+ | stageWidth | number | - | 画布宽度(必需) |
318
+ | stageHeight | number | - | 画布高度(必需) |
319
+ | width | number | 200 | 签名区域宽度 |
320
+ | height | number | 50 | 签名区域高度 |
321
+ | padding | number | 8 | 变换器内边距 |
322
+ | placeholder | string | '拖拽到签名位置' | 占位文本 |
323
+ | signature | string | - | 签名图片 URL |
324
+ | value | object | - | 受控的位置值 |
325
+ | onChange | function | - | 位置变化回调 |
326
+
327
+ ### useSignature
328
+
329
+ 签名画板 Hook,提供手写签名功能。
330
+
331
+ #### 返回的函数参数
332
+
333
+ | 参数 | 类型 | 默认值 | 说明 |
334
+ |------------|----------|-----------------|------------|
335
+ | filename | string | 'signature.png' | 签名文件名 |
336
+ | width | number | 200 | 签名画板宽度 |
337
+ | height | number | 50 | 签名画板高度 |
338
+ | onSuccess | function | - | 签名完成回调 |
339
+ | modalProps | object | - | Modal 组件属性 |
340
+
341
+ #### Hook 配置参数
342
+
343
+ | 参数 | 类型 | 默认值 | 说明 |
344
+ |--------|--------|-----|----------|
345
+ | width | number | 200 | 默认签名画板宽度 |
346
+ | height | number | 50 | 默认签名画板高度 |
package/dist/index.css ADDED
@@ -0,0 +1,64 @@
1
+ ._RgZXN {
2
+ margin: 0 auto;
3
+ position: relative;
4
+ max-width: 1200px;
5
+ width: 100%;
6
+ }
7
+ ._RgZXN .react-pdf__Page__canvas,
8
+ ._RgZXN .textLayer {
9
+ margin: 0 auto;
10
+ }
11
+
12
+ ._PAju1 {
13
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
14
+ }
15
+
16
+ ._N11Pj {
17
+ position: absolute;
18
+ top: 0;
19
+ left: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ z-index: 10;
23
+ }
24
+
25
+ ._IbVpf,
26
+ ._IIgqj {
27
+ position: absolute;
28
+ font-size: 30px;
29
+ top: calc(50% - 19px);
30
+ z-index: 10;
31
+ padding: 8px;
32
+ cursor: pointer;
33
+ opacity: 0.3;
34
+ }
35
+
36
+ ._JW3CT {
37
+ position: absolute;
38
+ bottom: 10px;
39
+ left: 50%;
40
+ transform: translateX(-50%);
41
+ color: #666666;
42
+ background-color: rgba(255, 255, 255, 0.5);
43
+ text-shadow: 0 0 8px white, 0 0 8px white;
44
+ border-radius: 4px;
45
+ }
46
+
47
+ ._IIgqj {
48
+ right: 0;
49
+ }
50
+
51
+ ._6TDb- {
52
+ border: 1px solid #cccccc;
53
+ border-radius: 4px;
54
+ }
55
+
56
+ ._2CGF4 {
57
+ width: 100%;
58
+ height: 100%;
59
+ }
60
+
61
+ ._kWe3k .ant-modal-confirm-paragraph {
62
+ max-width: unset;
63
+ }
64
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["style.module.scss"],"names":[],"mappings":"AAAA;EACE,cAAc;EACd,kBAAkB;EAClB,iBAAiB;EACjB,WAAW;AACb;AACA;;EAEE,cAAc;AAChB;;AAEA;EACE,wEAAwE;AAC1E;;AAEA;EACE,kBAAkB;EAClB,MAAM;EACN,OAAO;EACP,WAAW;EACX,YAAY;EACZ,WAAW;AACb;;AAEA;;EAEE,kBAAkB;EAClB,eAAe;EACf,qBAAqB;EACrB,WAAW;EACX,YAAY;EACZ,eAAe;EACf,YAAY;AACd;;AAEA;EACE,kBAAkB;EAClB,YAAY;EACZ,SAAS;EACT,2BAA2B;EAC3B,cAAc;EACd,0CAA0C;EAC1C,yCAAyC;EACzC,kBAAkB;AACpB;;AAEA;EACE,QAAQ;AACV;;AAEA;EACE,yBAAyB;EACzB,kBAAkB;AACpB;;AAEA;EACE,WAAW;EACX,YAAY;AACd;;AAEA;EACE,gBAAgB;AAClB","file":"index.css","sourcesContent":[".pdf-view-container {\n margin: 0 auto;\n position: relative;\n max-width: 1200px;\n width: 100%;\n}\n.pdf-view-container :global(.react-pdf__Page__canvas),\n.pdf-view-container :global(.textLayer) {\n margin: 0 auto;\n}\n\n.pdf-view {\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\n}\n\n.pdf-view-children {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 10;\n}\n\n.pdf-view-page-control-left,\n.pdf-view-page-control-right {\n position: absolute;\n font-size: 30px;\n top: calc(50% - 19px);\n z-index: 10;\n padding: 8px;\n cursor: pointer;\n opacity: 0.3;\n}\n\n.pdf-view-page-control-current {\n position: absolute;\n bottom: 10px;\n left: 50%;\n transform: translateX(-50%);\n color: #666666;\n background-color: rgba(255, 255, 255, 0.5);\n text-shadow: 0 0 8px white, 0 0 8px white;\n border-radius: 4px;\n}\n\n.pdf-view-page-control-right {\n right: 0;\n}\n\n.signature-container {\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n\n.signature-canvas {\n width: 100%;\n height: 100%;\n}\n\n.signature-modal :global .ant-modal-confirm-paragraph {\n max-width: unset;\n}"]}