@courtifyai/docx-render 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.
@@ -0,0 +1 @@
1
+ export { DocumentRenderer } from './document-renderer'
@@ -0,0 +1,692 @@
1
+ /**
2
+ * DOCX Render - 样式文件
3
+ * 文档分页渲染样式(仿 Word)
4
+ */
5
+
6
+ /* ===== 容器布局 ===== */
7
+ .docx-container {
8
+ width: 100%;
9
+ height: 100%;
10
+ overflow: hidden;
11
+ background-color: #525659;
12
+ font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif;
13
+ }
14
+
15
+ .docx-wrapper {
16
+ position: relative;
17
+ width: 100%;
18
+ height: 100%;
19
+ overflow: auto;
20
+ padding: 30px;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ gap: 30px;
25
+ }
26
+
27
+ /* ===== 页面元素 ===== */
28
+ .docx-page {
29
+ background: white;
30
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
31
+ box-sizing: border-box;
32
+ display: flex;
33
+ flex-direction: column;
34
+ position: relative;
35
+ overflow: hidden;
36
+ flex-shrink: 0;
37
+ /* 默认 A4 尺寸 */
38
+ width: 595.3pt;
39
+ min-height: 841.9pt;
40
+ padding: 72pt 90pt;
41
+ }
42
+
43
+ /* ===== Section 内容区 ===== */
44
+ .docx-section-content {
45
+ flex: 1;
46
+ z-index: 1;
47
+ }
48
+
49
+ /* ===== 页眉页脚 ===== */
50
+ .docx-header,
51
+ .docx-footer {
52
+ z-index: 1;
53
+ color: #666;
54
+ font-size: 10pt;
55
+ }
56
+
57
+ .docx-header {
58
+ padding-bottom: 12pt;
59
+ border-bottom: 1px solid #eee;
60
+ margin-bottom: 12pt;
61
+ }
62
+
63
+ .docx-footer {
64
+ padding-top: 12pt;
65
+ border-top: 1px solid #eee;
66
+ margin-top: auto;
67
+ }
68
+
69
+ /* ===== 文档主体 ===== */
70
+ .docx-body {
71
+ line-height: 1.5;
72
+ color: black;
73
+ }
74
+
75
+ /* ===== 段落样式 ===== */
76
+ .docx-p {
77
+ margin: 0pt;
78
+ min-height: 1em;
79
+ }
80
+
81
+ /* ===== 文本样式 ===== */
82
+ .docx-run {
83
+ white-space: pre-wrap;
84
+ overflow-wrap: break-word;
85
+ }
86
+
87
+ /* ===== 上标/下标 ===== */
88
+ .docx-superscript {
89
+ vertical-align: super;
90
+ font-size: 0.75em;
91
+ line-height: 0;
92
+ }
93
+
94
+ .docx-subscript {
95
+ vertical-align: sub;
96
+ font-size: 0.75em;
97
+ line-height: 0;
98
+ }
99
+
100
+ /* ===== 双删除线 ===== */
101
+ .docx-dstrike {
102
+ text-decoration: line-through;
103
+ text-decoration-style: double;
104
+ }
105
+
106
+ /* ===== Symbol 字符 ===== */
107
+ .docx-symbol {
108
+ display: inline;
109
+ }
110
+
111
+ /* ===== 下划线样式 ===== */
112
+ /* 单线(默认) */
113
+ .docx-underline-single {
114
+ text-decoration: underline;
115
+ text-decoration-style: solid;
116
+ }
117
+
118
+ /* 仅文字下划线 */
119
+ .docx-underline-words {
120
+ text-decoration: underline;
121
+ text-decoration-skip-ink: none;
122
+ }
123
+
124
+ /* 双线下划线 */
125
+ .docx-underline-double {
126
+ text-decoration: underline;
127
+ text-decoration-style: double;
128
+ }
129
+
130
+ /* 粗线下划线 */
131
+ .docx-underline-thick {
132
+ text-decoration: underline;
133
+ text-decoration-style: solid;
134
+ text-decoration-thickness: 2px;
135
+ }
136
+
137
+ /* 点线下划线 */
138
+ .docx-underline-dotted {
139
+ text-decoration: underline;
140
+ text-decoration-style: dotted;
141
+ }
142
+
143
+ /* 粗点线下划线 */
144
+ .docx-underline-dottedHeavy {
145
+ text-decoration: underline;
146
+ text-decoration-style: dotted;
147
+ text-decoration-thickness: 2px;
148
+ }
149
+
150
+ /* 虚线下划线 */
151
+ .docx-underline-dash {
152
+ text-decoration: underline;
153
+ text-decoration-style: dashed;
154
+ }
155
+
156
+ /* 粗虚线下划线 */
157
+ .docx-underline-dashedHeavy {
158
+ text-decoration: underline;
159
+ text-decoration-style: dashed;
160
+ text-decoration-thickness: 2px;
161
+ }
162
+
163
+ /* 长虚线下划线 */
164
+ .docx-underline-dashLong {
165
+ text-decoration: underline;
166
+ text-decoration-style: dashed;
167
+ }
168
+
169
+ /* 粗长虚线下划线 */
170
+ .docx-underline-dashLongHeavy {
171
+ text-decoration: underline;
172
+ text-decoration-style: dashed;
173
+ text-decoration-thickness: 2px;
174
+ }
175
+
176
+ /* 点划线下划线(使用背景渐变模拟) */
177
+ .docx-underline-dotDash {
178
+ text-decoration: none;
179
+ border-bottom: 1px dashed currentColor;
180
+ background-image: linear-gradient(90deg, currentColor 1px, transparent 1px);
181
+ background-size: 4px 1px;
182
+ background-repeat: repeat-x;
183
+ background-position: 0 100%;
184
+ }
185
+
186
+ /* 粗点划线下划线 */
187
+ .docx-underline-dashDotHeavy {
188
+ text-decoration: none;
189
+ border-bottom: 2px dashed currentColor;
190
+ }
191
+
192
+ /* 双点划线下划线 */
193
+ .docx-underline-dotDotDash {
194
+ text-decoration: none;
195
+ border-bottom: 1px dotted currentColor;
196
+ }
197
+
198
+ /* 粗双点划线下划线 */
199
+ .docx-underline-dashDotDotHeavy {
200
+ text-decoration: none;
201
+ border-bottom: 2px dotted currentColor;
202
+ }
203
+
204
+ /* 波浪线下划线 */
205
+ .docx-underline-wave {
206
+ text-decoration: underline;
207
+ text-decoration-style: wavy;
208
+ }
209
+
210
+ /* 粗波浪线下划线 */
211
+ .docx-underline-wavyHeavy {
212
+ text-decoration: underline;
213
+ text-decoration-style: wavy;
214
+ text-decoration-thickness: 2px;
215
+ }
216
+
217
+ /* 双波浪线下划线(使用双层模拟) */
218
+ .docx-underline-wavyDouble {
219
+ text-decoration: underline;
220
+ text-decoration-style: wavy;
221
+ position: relative;
222
+ }
223
+
224
+ .docx-underline-wavyDouble::after {
225
+ content: '';
226
+ position: absolute;
227
+ left: 0;
228
+ right: 0;
229
+ bottom: -3px;
230
+ border-bottom: 1px wavy currentColor;
231
+ text-decoration: underline wavy;
232
+ }
233
+
234
+ /* ===== Tab ===== */
235
+ .docx-tab {
236
+ display: inline-block;
237
+ min-width: 36pt;
238
+ }
239
+
240
+ /* ===== 编号/列表样式 ===== */
241
+ .docx-list-item {
242
+ display: flex;
243
+ align-items: baseline;
244
+ }
245
+
246
+ .docx-numbering-wrapper {
247
+ display: inline-block;
248
+ flex-shrink: 0;
249
+ min-width: 24pt;
250
+ text-align: right;
251
+ margin-right: 6pt;
252
+ }
253
+
254
+ .docx-numbering {
255
+ white-space: nowrap;
256
+ }
257
+
258
+ .docx-numbering-suffix {
259
+ display: inline-block;
260
+ }
261
+
262
+ /* ===== 评论高亮 ===== */
263
+ .docx-highlight {
264
+ background-color: rgba(251, 191, 36, 0.25);
265
+ border-bottom: 2px solid #fbbf24;
266
+ cursor: pointer;
267
+ transition: all 0.2s ease;
268
+ border-radius: 2px;
269
+ padding: 1px 2px;
270
+ margin: -1px -2px;
271
+ }
272
+
273
+ .docx-highlight:hover {
274
+ background-color: rgba(251, 191, 36, 0.4);
275
+ }
276
+
277
+ .docx-highlight--active {
278
+ background-color: rgba(245, 158, 11, 0.5);
279
+ border-bottom-color: #f59e0b;
280
+ }
281
+
282
+ /* ===== 评论容器层 ===== */
283
+ .docx-comments-layer {
284
+ position: fixed;
285
+ right: 20px;
286
+ top: 0;
287
+ bottom: 0;
288
+ width: 260px;
289
+ z-index: 1000;
290
+ pointer-events: none;
291
+ }
292
+
293
+ .docx-comment-bubble {
294
+ pointer-events: auto;
295
+ }
296
+
297
+ /* ===== 评论气泡 ===== */
298
+ .docx-comment-bubble {
299
+ position: relative;
300
+ width: 100%;
301
+ background: #fffbeb;
302
+ border: 1px solid #fcd34d;
303
+ border-left: 4px solid #f59e0b;
304
+ border-radius: 8px;
305
+ padding: 12px 14px;
306
+ font-size: 13px;
307
+ cursor: pointer;
308
+ transition: all 0.2s ease;
309
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
310
+ margin-bottom: 12px;
311
+ }
312
+
313
+ .docx-comment-bubble:hover {
314
+ box-shadow: 0 4px 12px rgba(245, 158, 11, 0.2);
315
+ transform: translateX(-2px);
316
+ }
317
+
318
+ .docx-comment-bubble--active {
319
+ background: #fef3c7;
320
+ border-color: #f59e0b;
321
+ box-shadow: 0 4px 16px rgba(245, 158, 11, 0.3);
322
+ }
323
+
324
+ .docx-comment-header {
325
+ display: flex;
326
+ align-items: center;
327
+ gap: 10px;
328
+ margin-bottom: 8px;
329
+ }
330
+
331
+ .docx-comment-avatar {
332
+ width: 28px;
333
+ height: 28px;
334
+ background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
335
+ border-radius: 50%;
336
+ display: flex;
337
+ align-items: center;
338
+ justify-content: center;
339
+ color: white;
340
+ font-size: 12px;
341
+ font-weight: 600;
342
+ flex-shrink: 0;
343
+ }
344
+
345
+ .docx-comment-meta {
346
+ flex: 1;
347
+ min-width: 0;
348
+ }
349
+
350
+ .docx-comment-author {
351
+ display: block;
352
+ font-weight: 600;
353
+ color: #92400e;
354
+ font-size: 13px;
355
+ white-space: nowrap;
356
+ overflow: hidden;
357
+ text-overflow: ellipsis;
358
+ }
359
+
360
+ .docx-comment-date {
361
+ display: block;
362
+ font-size: 11px;
363
+ color: #b45309;
364
+ margin-top: 1px;
365
+ }
366
+
367
+ .docx-comment-content {
368
+ color: #78350f;
369
+ line-height: 1.5;
370
+ word-wrap: break-word;
371
+ }
372
+
373
+ .docx-comment-actions {
374
+ display: flex;
375
+ gap: 6px;
376
+ margin-top: 10px;
377
+ padding-top: 10px;
378
+ border-top: 1px solid #fcd34d;
379
+ opacity: 0;
380
+ transition: opacity 0.2s ease;
381
+ }
382
+
383
+ .docx-comment-bubble:hover .docx-comment-actions {
384
+ opacity: 1;
385
+ }
386
+
387
+ .docx-comment-btn {
388
+ display: flex;
389
+ align-items: center;
390
+ justify-content: center;
391
+ width: 26px;
392
+ height: 26px;
393
+ padding: 0;
394
+ border: none;
395
+ background: white;
396
+ border-radius: 4px;
397
+ cursor: pointer;
398
+ color: #92400e;
399
+ transition: all 0.15s ease;
400
+ }
401
+
402
+ .docx-comment-btn:hover {
403
+ background: #fef3c7;
404
+ }
405
+
406
+ .docx-comment-btn.delete:hover {
407
+ background: #fef2f2;
408
+ color: #dc2626;
409
+ }
410
+
411
+ /* ===== 评论标记 ===== */
412
+ .docx-comment-ref {
413
+ cursor: pointer;
414
+ font-size: 12px;
415
+ vertical-align: super;
416
+ margin-left: 2px;
417
+ opacity: 0.7;
418
+ transition: opacity 0.2s;
419
+ }
420
+
421
+ .docx-comment-ref:hover {
422
+ opacity: 1;
423
+ }
424
+
425
+ .docx-comment-start,
426
+ .docx-comment-end {
427
+ display: none;
428
+ }
429
+
430
+ /* ===== 表格样式 ===== */
431
+ .docx-table {
432
+ border-collapse: collapse;
433
+ margin: 6pt 0;
434
+ font-size: inherit;
435
+ table-layout: fixed;
436
+ width: 100%;
437
+ }
438
+
439
+ .docx-tr {
440
+ /* 默认样式 */
441
+ }
442
+
443
+ .docx-td {
444
+ /* 边框由解析的样式控制,不设置默认边框 */
445
+ padding: 4pt 6pt;
446
+ vertical-align: top;
447
+ word-wrap: break-word;
448
+ overflow-wrap: break-word;
449
+ }
450
+
451
+ .docx-table .docx-p {
452
+ margin: 0;
453
+ min-height: auto;
454
+ }
455
+
456
+ /* ===== 书签锚点 ===== */
457
+ .docx-bookmark {
458
+ /* 不占用空间的锚点元素 */
459
+ display: inline;
460
+ position: relative;
461
+ }
462
+
463
+ /* ===== 超链接 ===== */
464
+ .docx-link {
465
+ color: #0563c1;
466
+ text-decoration: underline;
467
+ }
468
+
469
+ .docx-link:hover {
470
+ color: #954f72;
471
+ }
472
+
473
+ /* 书签锚点跳转的平滑滚动 */
474
+ .docx-link[href^="#"] {
475
+ cursor: pointer;
476
+ }
477
+
478
+ /* ===== 图片 ===== */
479
+ .docx-image {
480
+ max-width: 100%;
481
+ height: auto;
482
+ }
483
+
484
+ .docx-drawing {
485
+ display: inline-block;
486
+ }
487
+
488
+ /* ===== 脚注/尾注引用(上标数字) ===== */
489
+ .docx-footnote-ref,
490
+ .docx-endnote-ref {
491
+ color: #0066cc;
492
+ cursor: pointer;
493
+ font-size: 0.8em;
494
+ vertical-align: super;
495
+ line-height: 0;
496
+ padding: 0 2px;
497
+ transition: color 0.2s;
498
+ }
499
+
500
+ .docx-footnote-ref:hover,
501
+ .docx-endnote-ref:hover {
502
+ color: #003d99;
503
+ text-decoration: underline;
504
+ }
505
+
506
+ /* ===== 脚注区域 ===== */
507
+ .docx-footnotes-section {
508
+ margin-top: auto;
509
+ padding-top: 12pt;
510
+ font-size: 9pt;
511
+ color: #333;
512
+ }
513
+
514
+ .docx-footnotes-separator {
515
+ border: none;
516
+ border-top: 1px solid #ccc;
517
+ margin: 0 0 8pt 0;
518
+ width: 33%;
519
+ }
520
+
521
+ .docx-footnotes-list {
522
+ margin: 0;
523
+ padding-left: 20pt;
524
+ list-style-type: decimal;
525
+ }
526
+
527
+ .docx-footnote {
528
+ margin-bottom: 4pt;
529
+ line-height: 1.4;
530
+ }
531
+
532
+ .docx-footnote .docx-p {
533
+ display: inline;
534
+ margin: 0;
535
+ min-height: auto;
536
+ }
537
+
538
+ /* ===== 尾注区域 ===== */
539
+ .docx-endnotes-section {
540
+ background: white;
541
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
542
+ box-sizing: border-box;
543
+ width: 595.3pt;
544
+ padding: 40pt 90pt;
545
+ margin-top: 30px;
546
+ }
547
+
548
+ .docx-endnotes-title {
549
+ font-size: 14pt;
550
+ font-weight: bold;
551
+ margin: 0 0 12pt 0;
552
+ padding-bottom: 8pt;
553
+ border-bottom: 2px solid #333;
554
+ }
555
+
556
+ .docx-endnotes-list {
557
+ margin: 0;
558
+ padding-left: 20pt;
559
+ list-style-type: decimal;
560
+ font-size: 10pt;
561
+ }
562
+
563
+ .docx-endnote {
564
+ margin-bottom: 8pt;
565
+ line-height: 1.5;
566
+ }
567
+
568
+ .docx-endnote .docx-p {
569
+ display: inline;
570
+ margin: 0;
571
+ min-height: auto;
572
+ }
573
+
574
+ /* ===== 分页符(在非分页模式下显示) ===== */
575
+ .docx-page-break {
576
+ height: 40px;
577
+ border-bottom: 2px dashed #ccc;
578
+ margin: 20px 0;
579
+ position: relative;
580
+ }
581
+
582
+ .docx-page-break::after {
583
+ content: '分页';
584
+ position: absolute;
585
+ left: 50%;
586
+ bottom: -10px;
587
+ transform: translateX(-50%);
588
+ background: white;
589
+ padding: 0 12px;
590
+ font-size: 12px;
591
+ color: #999;
592
+ }
593
+
594
+ /* ===== 分栏分隔符 ===== */
595
+ .docx-column-break {
596
+ display: block;
597
+ break-after: column;
598
+ }
599
+
600
+ /* ===== SVG 连线层 ===== */
601
+ .docx-lines {
602
+ position: fixed;
603
+ top: 0;
604
+ left: 0;
605
+ width: 100vw;
606
+ height: 100vh;
607
+ pointer-events: none;
608
+ z-index: 999;
609
+ }
610
+
611
+ /* ===== 滚动条 ===== */
612
+ .docx-wrapper::-webkit-scrollbar {
613
+ width: 12px;
614
+ height: 12px;
615
+ }
616
+
617
+ .docx-wrapper::-webkit-scrollbar-track {
618
+ background: #3d3d3d;
619
+ }
620
+
621
+ .docx-wrapper::-webkit-scrollbar-thumb {
622
+ background: #666;
623
+ border-radius: 6px;
624
+ }
625
+
626
+ .docx-wrapper::-webkit-scrollbar-thumb:hover {
627
+ background: #888;
628
+ }
629
+
630
+ /* ===== 响应式 ===== */
631
+ @media (max-width: 900px) {
632
+ .docx-wrapper {
633
+ padding: 16px;
634
+ }
635
+
636
+ .docx-page {
637
+ width: 100%;
638
+ min-height: auto;
639
+ padding: 40px 30px;
640
+ }
641
+
642
+ .docx-comments-layer {
643
+ display: none;
644
+ }
645
+
646
+ .docx-lines {
647
+ display: none;
648
+ }
649
+ }
650
+
651
+ /* ===== 打印样式 ===== */
652
+ @media print {
653
+ .docx-container {
654
+ background: white;
655
+ }
656
+
657
+ .docx-wrapper {
658
+ padding: 0;
659
+ overflow: visible;
660
+ display: block;
661
+ background: white;
662
+ }
663
+
664
+ .docx-page {
665
+ box-shadow: none;
666
+ margin: 0;
667
+ page-break-after: always;
668
+ width: 100%;
669
+ min-height: 100vh;
670
+ }
671
+
672
+ .docx-page:last-child {
673
+ page-break-after: auto;
674
+ }
675
+
676
+ .docx-comments-layer {
677
+ display: none;
678
+ }
679
+
680
+ .docx-highlight {
681
+ background: none;
682
+ border-bottom: none;
683
+ }
684
+
685
+ .docx-lines {
686
+ display: none;
687
+ }
688
+
689
+ .docx-page-break {
690
+ display: none;
691
+ }
692
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 主题模块
3
+ * 解析 DOCX 主题文件(word/theme/theme1.xml)
4
+ * 支持主题颜色和字体方案解析
5
+ */
6
+
7
+ export { parseTheme, parseColorScheme, parseFontScheme } from './theme-parser'
8
+ export { resolveThemeColor, applyTintShade, resolveThemeFont } from './theme-utils'