@cj-tech-master/excelts 9.5.0 → 9.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/modules/pdf/excel-bridge.js +27 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +74 -9
- package/dist/browser/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/browser/modules/pdf/render/style-converter.js +98 -1
- package/dist/browser/modules/pdf/types.d.ts +1 -0
- package/dist/browser/modules/word/color-utils.d.ts +18 -0
- package/dist/browser/modules/word/color-utils.js +94 -0
- package/dist/browser/modules/word/content-types.d.ts +15 -15
- package/dist/browser/modules/word/content-types.js +39 -43
- package/dist/browser/modules/word/crypto.d.ts +17 -0
- package/dist/browser/modules/word/crypto.js +18 -0
- package/dist/browser/modules/word/document-io.d.ts +58 -0
- package/dist/browser/modules/word/document-io.js +239 -0
- package/dist/browser/modules/word/document.d.ts +64 -135
- package/dist/browser/modules/word/document.js +207 -469
- package/dist/browser/modules/word/docx-packager.js +90 -90
- package/dist/browser/modules/word/html-renderer.js +1 -1
- package/dist/browser/modules/word/html.d.ts +13 -0
- package/dist/browser/modules/word/html.js +12 -0
- package/dist/browser/modules/word/index.base.d.ts +6 -9
- package/dist/browser/modules/word/index.base.js +7 -10
- package/dist/browser/modules/word/namespaces.d.ts +159 -0
- package/dist/browser/modules/word/namespaces.js +189 -0
- package/dist/browser/modules/word/relationships.d.ts +15 -16
- package/dist/browser/modules/word/relationships.js +37 -45
- package/dist/cjs/modules/pdf/excel-bridge.js +27 -1
- package/dist/cjs/modules/pdf/render/layout-engine.js +74 -9
- package/dist/cjs/modules/pdf/render/style-converter.js +98 -1
- package/dist/cjs/modules/word/color-utils.js +97 -0
- package/dist/cjs/modules/word/content-types.js +44 -45
- package/dist/cjs/modules/word/crypto.js +34 -0
- package/dist/cjs/modules/word/document-io.js +244 -0
- package/dist/cjs/modules/word/document.js +209 -473
- package/dist/cjs/modules/word/docx-packager.js +88 -88
- package/dist/cjs/modules/word/html-renderer.js +2 -2
- package/dist/cjs/modules/word/html.js +16 -0
- package/dist/cjs/modules/word/index.base.js +17 -27
- package/dist/cjs/modules/word/namespaces.js +192 -0
- package/dist/cjs/modules/word/relationships.js +42 -47
- package/dist/esm/modules/pdf/excel-bridge.js +27 -1
- package/dist/esm/modules/pdf/render/layout-engine.js +74 -9
- package/dist/esm/modules/pdf/render/style-converter.js +98 -1
- package/dist/esm/modules/word/color-utils.js +94 -0
- package/dist/esm/modules/word/content-types.js +39 -43
- package/dist/esm/modules/word/crypto.js +18 -0
- package/dist/esm/modules/word/document-io.js +239 -0
- package/dist/esm/modules/word/document.js +207 -469
- package/dist/esm/modules/word/docx-packager.js +90 -90
- package/dist/esm/modules/word/html-renderer.js +1 -1
- package/dist/esm/modules/word/html.js +12 -0
- package/dist/esm/modules/word/index.base.js +7 -10
- package/dist/esm/modules/word/namespaces.js +189 -0
- package/dist/esm/modules/word/relationships.js +37 -45
- package/dist/iife/excelts.iife.js +153 -11
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +4 -4
- package/dist/types/modules/pdf/render/style-converter.d.ts +1 -1
- package/dist/types/modules/pdf/types.d.ts +1 -0
- package/dist/types/modules/word/color-utils.d.ts +18 -0
- package/dist/types/modules/word/content-types.d.ts +15 -15
- package/dist/types/modules/word/crypto.d.ts +17 -0
- package/dist/types/modules/word/document-io.d.ts +58 -0
- package/dist/types/modules/word/document.d.ts +64 -135
- package/dist/types/modules/word/html.d.ts +13 -0
- package/dist/types/modules/word/index.base.d.ts +6 -9
- package/dist/types/modules/word/namespaces.d.ts +159 -0
- package/dist/types/modules/word/relationships.d.ts +15 -16
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DOCX Module — Sub-namespace objects
|
|
4
|
+
*
|
|
5
|
+
* Groups flat builder helpers into logical namespaces for better
|
|
6
|
+
* IDE discoverability. These are re-exports aggregated into objects;
|
|
7
|
+
* since they reference the same underlying functions, tree-shaking
|
|
8
|
+
* still applies at the individual function level for consumers who
|
|
9
|
+
* import the flat named exports instead.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { Run, Paragraph, Table, Math, Field } from "excelts/word";
|
|
14
|
+
*
|
|
15
|
+
* const doc = Document.create();
|
|
16
|
+
* Document.addParagraphElement(doc, Paragraph.create([
|
|
17
|
+
* Run.bold("Hello"),
|
|
18
|
+
* Run.text(" world")
|
|
19
|
+
* ]));
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.Query = exports.Sdt = exports.Drawing = exports.Table = exports.Math = exports.TrackChanges = exports.Comment = exports.Paragraph = exports.Field = exports.Run = void 0;
|
|
24
|
+
const document_1 = require("./document");
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Run namespace — text run constructors
|
|
27
|
+
// =============================================================================
|
|
28
|
+
/** Namespace for creating text runs (inline content). */
|
|
29
|
+
exports.Run = {
|
|
30
|
+
text: document_1.text,
|
|
31
|
+
bold: document_1.bold,
|
|
32
|
+
italic: document_1.italic,
|
|
33
|
+
pageBreak: document_1.pageBreak,
|
|
34
|
+
lineBreak: document_1.lineBreak,
|
|
35
|
+
columnBreak: document_1.columnBreak,
|
|
36
|
+
tab: document_1.tab,
|
|
37
|
+
positionalTab: document_1.positionalTab,
|
|
38
|
+
ruby: document_1.ruby,
|
|
39
|
+
carriageReturn: document_1.carriageReturn,
|
|
40
|
+
noBreakHyphen: document_1.noBreakHyphen,
|
|
41
|
+
softHyphen: document_1.softHyphen,
|
|
42
|
+
symbol: document_1.symbol
|
|
43
|
+
};
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Field namespace — field code constructors
|
|
46
|
+
// =============================================================================
|
|
47
|
+
/** Namespace for creating field codes. */
|
|
48
|
+
exports.Field = {
|
|
49
|
+
create: document_1.field,
|
|
50
|
+
pageNumber: document_1.pageNumberField,
|
|
51
|
+
totalPages: document_1.totalPagesField,
|
|
52
|
+
sectionPages: document_1.sectionPagesField,
|
|
53
|
+
section: document_1.sectionField,
|
|
54
|
+
date: document_1.dateField,
|
|
55
|
+
sequence: document_1.sequenceField,
|
|
56
|
+
time: document_1.timeField,
|
|
57
|
+
author: document_1.authorField,
|
|
58
|
+
title: document_1.titleField,
|
|
59
|
+
subject: document_1.subjectField,
|
|
60
|
+
keywords: document_1.keywordsField,
|
|
61
|
+
fileName: document_1.fileNameField,
|
|
62
|
+
fileSize: document_1.fileSizeField,
|
|
63
|
+
styleRef: document_1.styleRefField,
|
|
64
|
+
ref: document_1.refField,
|
|
65
|
+
pageRef: document_1.pageRefField,
|
|
66
|
+
noteRef: document_1.noteRefField,
|
|
67
|
+
hyperlink: document_1.hyperlinkField,
|
|
68
|
+
quote: document_1.quoteField,
|
|
69
|
+
toc: document_1.tocField,
|
|
70
|
+
tc: document_1.tcField,
|
|
71
|
+
indexEntry: document_1.indexEntryField,
|
|
72
|
+
index: document_1.indexField,
|
|
73
|
+
condition: document_1.ifField,
|
|
74
|
+
includeText: document_1.includeTextField,
|
|
75
|
+
includePicture: document_1.includePictureField,
|
|
76
|
+
formText: document_1.formTextField,
|
|
77
|
+
formCheckbox: document_1.formCheckboxField,
|
|
78
|
+
formDropdown: document_1.formDropdownField
|
|
79
|
+
};
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// Paragraph namespace — paragraph constructors
|
|
82
|
+
// =============================================================================
|
|
83
|
+
/** Namespace for creating paragraphs. */
|
|
84
|
+
exports.Paragraph = {
|
|
85
|
+
create: document_1.paragraph,
|
|
86
|
+
text: document_1.textParagraph,
|
|
87
|
+
heading: document_1.heading,
|
|
88
|
+
hyperlink: document_1.hyperlink,
|
|
89
|
+
bookmarkStart: document_1.bookmarkStart,
|
|
90
|
+
bookmarkEnd: document_1.bookmarkEnd
|
|
91
|
+
};
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// Comment namespace — comment markers
|
|
94
|
+
// =============================================================================
|
|
95
|
+
/** Namespace for comment-related markers. */
|
|
96
|
+
exports.Comment = {
|
|
97
|
+
rangeStart: document_1.commentRangeStart,
|
|
98
|
+
rangeEnd: document_1.commentRangeEnd,
|
|
99
|
+
reference: document_1.commentReference
|
|
100
|
+
};
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// TrackChanges namespace — revision markers
|
|
103
|
+
// =============================================================================
|
|
104
|
+
/** Namespace for track-changes (revision) markers. */
|
|
105
|
+
exports.TrackChanges = {
|
|
106
|
+
insertedRun: document_1.insertedRun,
|
|
107
|
+
deletedRun: document_1.deletedRun,
|
|
108
|
+
movedFromRun: document_1.movedFromRun,
|
|
109
|
+
movedToRun: document_1.movedToRun,
|
|
110
|
+
moveFromRangeStart: document_1.moveFromRangeStart,
|
|
111
|
+
moveFromRangeEnd: document_1.moveFromRangeEnd,
|
|
112
|
+
moveToRangeStart: document_1.moveToRangeStart,
|
|
113
|
+
moveToRangeEnd: document_1.moveToRangeEnd
|
|
114
|
+
};
|
|
115
|
+
// =============================================================================
|
|
116
|
+
// Math namespace — Office Math constructors
|
|
117
|
+
// =============================================================================
|
|
118
|
+
/** Namespace for OMML (Office Math) content. */
|
|
119
|
+
exports.Math = {
|
|
120
|
+
block: document_1.mathBlock,
|
|
121
|
+
run: document_1.mathRun,
|
|
122
|
+
fraction: document_1.mathFraction,
|
|
123
|
+
sqrt: document_1.mathSqrt,
|
|
124
|
+
root: document_1.mathRoot,
|
|
125
|
+
sum: document_1.mathSum,
|
|
126
|
+
integral: document_1.mathIntegral,
|
|
127
|
+
product: document_1.mathProduct,
|
|
128
|
+
superScript: document_1.mathSuperScript,
|
|
129
|
+
subScript: document_1.mathSubScript,
|
|
130
|
+
subSuperScript: document_1.mathSubSuperScript,
|
|
131
|
+
preSubSuperScript: document_1.mathPreSubSuperScript,
|
|
132
|
+
phantom: document_1.mathPhantom,
|
|
133
|
+
groupChar: document_1.mathGroupChar,
|
|
134
|
+
borderBox: document_1.mathBorderBox,
|
|
135
|
+
delimiter: document_1.mathDelimiter,
|
|
136
|
+
nary: document_1.mathNary,
|
|
137
|
+
func: document_1.mathFunction,
|
|
138
|
+
limit: document_1.mathLimit,
|
|
139
|
+
matrix: document_1.mathMatrix,
|
|
140
|
+
accent: document_1.mathAccent,
|
|
141
|
+
bar: document_1.mathBar,
|
|
142
|
+
box: document_1.mathBox,
|
|
143
|
+
equationArray: document_1.mathEquationArray
|
|
144
|
+
};
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Table namespace — table constructors
|
|
147
|
+
// =============================================================================
|
|
148
|
+
/** Namespace for creating tables. */
|
|
149
|
+
exports.Table = {
|
|
150
|
+
create: document_1.table,
|
|
151
|
+
simple: document_1.simpleTable,
|
|
152
|
+
row: document_1.row,
|
|
153
|
+
cell: document_1.cell,
|
|
154
|
+
border: document_1.border,
|
|
155
|
+
gridBorders: document_1.gridBorders
|
|
156
|
+
};
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Drawing namespace — images, shapes, charts
|
|
159
|
+
// =============================================================================
|
|
160
|
+
/** Namespace for drawings (images, shapes, charts). */
|
|
161
|
+
exports.Drawing = {
|
|
162
|
+
floatingImage: document_1.floatingImage,
|
|
163
|
+
shape: document_1.drawingShape,
|
|
164
|
+
chart: document_1.chart
|
|
165
|
+
};
|
|
166
|
+
// =============================================================================
|
|
167
|
+
// Sdt namespace — structured document tags
|
|
168
|
+
// =============================================================================
|
|
169
|
+
/** Namespace for structured document tags (content controls). */
|
|
170
|
+
exports.Sdt = {
|
|
171
|
+
create: document_1.structuredDocumentTag,
|
|
172
|
+
checkBox: document_1.checkBox
|
|
173
|
+
};
|
|
174
|
+
// =============================================================================
|
|
175
|
+
// Query namespace — document query/search functions
|
|
176
|
+
// =============================================================================
|
|
177
|
+
/** Namespace for querying/searching document content. */
|
|
178
|
+
exports.Query = {
|
|
179
|
+
search: document_1.searchText,
|
|
180
|
+
replace: document_1.replaceText,
|
|
181
|
+
mailMerge: document_1.mailMerge,
|
|
182
|
+
paragraphCount: document_1.paragraphCount,
|
|
183
|
+
countWords: document_1.countWords,
|
|
184
|
+
getHeadings: document_1.getHeadings,
|
|
185
|
+
findBookmark: document_1.findBookmark,
|
|
186
|
+
findComment: document_1.findComment,
|
|
187
|
+
listImages: document_1.listImages,
|
|
188
|
+
listTables: document_1.listTables,
|
|
189
|
+
listHyperlinks: document_1.listHyperlinks,
|
|
190
|
+
tableCount: document_1.tableCount,
|
|
191
|
+
extractText: document_1.extractText
|
|
192
|
+
};
|
|
@@ -4,57 +4,52 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Manages OPC relationships for the DOCX package.
|
|
6
6
|
* Generates .rels files for package-level and part-level relationships.
|
|
7
|
+
* Uses a plain data record + free functions for tree-shakeability.
|
|
7
8
|
*/
|
|
8
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
10
|
+
exports.createRelationships = createRelationships;
|
|
11
|
+
exports.addRelationship = addRelationship;
|
|
12
|
+
exports.addRelationshipWithId = addRelationshipWithId;
|
|
13
|
+
exports.getRelationshipCount = getRelationshipCount;
|
|
14
|
+
exports.renderRelationships = renderRelationships;
|
|
10
15
|
const constants_1 = require("./constants");
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Keep nextId above any manually-assigned IDs
|
|
29
|
-
const num = parseInt(id.replace("rId", ""), 10);
|
|
30
|
-
if (!isNaN(num) && num >= this._nextId) {
|
|
31
|
-
this._nextId = num + 1;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/** Get all relationships. */
|
|
35
|
-
get relationships() {
|
|
36
|
-
return this._rels;
|
|
37
|
-
}
|
|
38
|
-
/** Get the number of relationships. */
|
|
39
|
-
get count() {
|
|
40
|
-
return this._rels.length;
|
|
16
|
+
/** Create a new empty RelationshipsState. */
|
|
17
|
+
function createRelationships() {
|
|
18
|
+
return { rels: [], nextId: 1 };
|
|
19
|
+
}
|
|
20
|
+
/** Add a relationship and return its assigned rId. */
|
|
21
|
+
function addRelationship(state, type, target, targetMode) {
|
|
22
|
+
const id = `rId${state.nextId++}`;
|
|
23
|
+
state.rels.push({ id, type, target, targetMode });
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
/** Add a relationship with a specific ID. */
|
|
27
|
+
function addRelationshipWithId(state, id, type, target, targetMode) {
|
|
28
|
+
state.rels.push({ id, type, target, targetMode });
|
|
29
|
+
// Keep nextId above any manually-assigned IDs
|
|
30
|
+
const num = parseInt(id.replace("rId", ""), 10);
|
|
31
|
+
if (!isNaN(num) && num >= state.nextId) {
|
|
32
|
+
state.nextId = num + 1;
|
|
41
33
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
}
|
|
35
|
+
/** Get the number of relationships. */
|
|
36
|
+
function getRelationshipCount(state) {
|
|
37
|
+
return state.rels.length;
|
|
38
|
+
}
|
|
39
|
+
/** Render the relationships XML to a sink. */
|
|
40
|
+
function renderRelationships(state, xml) {
|
|
41
|
+
xml.openXml(constants_1.STD_DOC_ATTRIBUTES);
|
|
42
|
+
xml.openNode("Relationships", { xmlns: constants_1.NS_PKG_RELS });
|
|
43
|
+
for (const rel of state.rels) {
|
|
44
|
+
const attrs = {
|
|
45
|
+
Id: rel.id,
|
|
46
|
+
Type: rel.type,
|
|
47
|
+
Target: rel.target
|
|
48
|
+
};
|
|
49
|
+
if (rel.targetMode) {
|
|
50
|
+
attrs.TargetMode = rel.targetMode;
|
|
56
51
|
}
|
|
57
|
-
xml.
|
|
52
|
+
xml.leafNode("Relationship", attrs);
|
|
58
53
|
}
|
|
54
|
+
xml.closeNode();
|
|
59
55
|
}
|
|
60
|
-
exports.RelationshipManager = RelationshipManager;
|
|
@@ -187,6 +187,31 @@ async function convertSheet(ws, workbook) {
|
|
|
187
187
|
right: dimensions.model.right
|
|
188
188
|
}
|
|
189
189
|
: { top: 0, left: 0, bottom: 0, right: 0 };
|
|
190
|
+
// Expand bounds to include cells that only have styles (borders, fills, fonts)
|
|
191
|
+
// but no values — these are not tracked by dimensions.
|
|
192
|
+
if (hasData) {
|
|
193
|
+
for (let r = bounds.top; r <= bounds.bottom; r++) {
|
|
194
|
+
const row = ws.findRow(r);
|
|
195
|
+
if (!row) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
row.eachCell({ includeEmpty: true }, cell => {
|
|
199
|
+
if (cell.col > bounds.right) {
|
|
200
|
+
const hasStyle = cell.style &&
|
|
201
|
+
((cell.style.border &&
|
|
202
|
+
(cell.style.border.top ||
|
|
203
|
+
cell.style.border.right ||
|
|
204
|
+
cell.style.border.bottom ||
|
|
205
|
+
cell.style.border.left)) ||
|
|
206
|
+
cell.style.fill ||
|
|
207
|
+
cell.style.font);
|
|
208
|
+
if (hasStyle || (cell.type !== ValueType.Null && cell.type !== ValueType.Merge)) {
|
|
209
|
+
bounds.right = cell.col;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
190
215
|
// Convert columns
|
|
191
216
|
const columns = new Map();
|
|
192
217
|
if (hasData) {
|
|
@@ -480,7 +505,8 @@ function convertColor(color) {
|
|
|
480
505
|
return {
|
|
481
506
|
argb: color.argb,
|
|
482
507
|
theme: color.theme,
|
|
483
|
-
tint: color.tint
|
|
508
|
+
tint: color.tint,
|
|
509
|
+
indexed: color.indexed
|
|
484
510
|
};
|
|
485
511
|
}
|
|
486
512
|
function convertFill(fill) {
|
|
@@ -551,7 +551,7 @@ function countWrapLines(cell, fontSize, scaleFactor, sheet, fontManager, options
|
|
|
551
551
|
if (value && typeof value === "object" && "richText" in value) {
|
|
552
552
|
const runs = value.richText;
|
|
553
553
|
if (runs.length > 0) {
|
|
554
|
-
const wrappedCount = countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontManager, options);
|
|
554
|
+
const wrappedCount = countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontManager, options, cell.style?.font);
|
|
555
555
|
return Math.max(lineCount, wrappedCount);
|
|
556
556
|
}
|
|
557
557
|
}
|
|
@@ -571,7 +571,10 @@ function countWrapLines(cell, fontSize, scaleFactor, sheet, fontManager, options
|
|
|
571
571
|
* This mirrors the logic in wrapRichTextLines (page-renderer) so that
|
|
572
572
|
* the row height calculation matches the actual rendering.
|
|
573
573
|
*/
|
|
574
|
-
function countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontManager, options) {
|
|
574
|
+
function countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontManager, options, cellFont) {
|
|
575
|
+
// Use cell-level font as fallback for runs without their own font
|
|
576
|
+
const defaultFamily = cellFont?.name ?? options.defaultFontFamily;
|
|
577
|
+
const defaultSize = cellFont?.size ?? options.defaultFontSize;
|
|
575
578
|
// Build character-to-run mapping
|
|
576
579
|
const runForChar = [];
|
|
577
580
|
for (let ri = 0; ri < runs.length; ri++) {
|
|
@@ -579,9 +582,20 @@ function countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontMan
|
|
|
579
582
|
runForChar.push(ri);
|
|
580
583
|
}
|
|
581
584
|
}
|
|
582
|
-
// Resolve font resources for each run
|
|
585
|
+
// Resolve font resources for each run (with cell font inheritance)
|
|
583
586
|
const runResources = runs.map(run => {
|
|
584
|
-
const
|
|
587
|
+
const effectiveRunFont = run.font
|
|
588
|
+
? {
|
|
589
|
+
name: run.font.name ?? cellFont?.name,
|
|
590
|
+
size: run.font.size ?? cellFont?.size,
|
|
591
|
+
bold: run.font.bold ?? cellFont?.bold,
|
|
592
|
+
italic: run.font.italic ?? cellFont?.italic,
|
|
593
|
+
strike: run.font.strike ?? cellFont?.strike,
|
|
594
|
+
underline: run.font.underline ?? cellFont?.underline,
|
|
595
|
+
color: run.font.color ?? cellFont?.color
|
|
596
|
+
}
|
|
597
|
+
: cellFont;
|
|
598
|
+
const fontProps = extractFontProperties(effectiveRunFont, defaultFamily, defaultSize);
|
|
585
599
|
const pdfFontName = resolvePdfFontName(fontProps.fontFamily, fontProps.bold, fontProps.italic);
|
|
586
600
|
return fontManager.hasEmbeddedFont()
|
|
587
601
|
? fontManager.getEmbeddedResourceName()
|
|
@@ -589,7 +603,15 @@ function countRichTextWrapLines(text, runs, scaleFactor, effectiveWidth, fontMan
|
|
|
589
603
|
});
|
|
590
604
|
// Resolve scaled font sizes for each run
|
|
591
605
|
const runFontSizes = runs.map(run => {
|
|
592
|
-
const
|
|
606
|
+
const effectiveRunFont = run.font
|
|
607
|
+
? {
|
|
608
|
+
name: run.font.name ?? cellFont?.name,
|
|
609
|
+
size: run.font.size ?? cellFont?.size,
|
|
610
|
+
bold: run.font.bold ?? cellFont?.bold,
|
|
611
|
+
italic: run.font.italic ?? cellFont?.italic
|
|
612
|
+
}
|
|
613
|
+
: cellFont;
|
|
614
|
+
const fontProps = extractFontProperties(effectiveRunFont, defaultFamily, defaultSize);
|
|
593
615
|
return fontProps.fontSize * scaleFactor;
|
|
594
616
|
});
|
|
595
617
|
// Measure a range of fullText using per-character run font sizes
|
|
@@ -861,8 +883,10 @@ function buildLayoutCell(cell, x, y, width, height, colSpan, rowSpan, options, f
|
|
|
861
883
|
// Track non-WinAnsi code points for Type3 fallback font generation
|
|
862
884
|
fontManager.trackText(text);
|
|
863
885
|
}
|
|
864
|
-
// Rich text runs
|
|
865
|
-
|
|
886
|
+
// Rich text runs — pass cell-level font as the fallback for runs without
|
|
887
|
+
// their own font definition (e.g. the first run often has no font object
|
|
888
|
+
// and should inherit the cell's style font including bold/italic).
|
|
889
|
+
const richText = buildRichTextRuns(cell, options, fontManager, scaleFactor, style.font);
|
|
866
890
|
const borders = excelBordersToPdf(style.border);
|
|
867
891
|
return {
|
|
868
892
|
text,
|
|
@@ -1305,6 +1329,30 @@ function computeTextOverflows(cellGrid, rowPage, colGroup, visibleRows, visibleC
|
|
|
1305
1329
|
}
|
|
1306
1330
|
if (overflowAvailable > 0) {
|
|
1307
1331
|
cell.textOverflowWidth = Math.min(overflowNeeded, overflowAvailable);
|
|
1332
|
+
// Hide internal vertical borders in the overflow region.
|
|
1333
|
+
// In Excel, when text overflows into adjacent empty cells, the shared
|
|
1334
|
+
// vertical borders between them are not drawn (the text appears to
|
|
1335
|
+
// span across seamlessly). We suppress:
|
|
1336
|
+
// - The overflowing cell's right border
|
|
1337
|
+
// - Each covered neighbor's left border (and right border if fully covered)
|
|
1338
|
+
let accumulated = 0;
|
|
1339
|
+
const actualOverflow = cell.textOverflowWidth;
|
|
1340
|
+
// Remove the source cell's right border if text overflows
|
|
1341
|
+
cell.borders.right = null;
|
|
1342
|
+
for (let j = gci + 1; j < colGroup.length; j++) {
|
|
1343
|
+
const neighborCell = cellGrid.get(`${ri}:${j}`);
|
|
1344
|
+
if (!neighborCell) {
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
// Remove the neighbor's left border (shared edge with previous cell)
|
|
1348
|
+
neighborCell.borders.left = null;
|
|
1349
|
+
accumulated += groupColWidths[j];
|
|
1350
|
+
if (accumulated >= actualOverflow) {
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1353
|
+
// If fully covered, also remove the neighbor's right border
|
|
1354
|
+
neighborCell.borders.right = null;
|
|
1355
|
+
}
|
|
1308
1356
|
}
|
|
1309
1357
|
}
|
|
1310
1358
|
}
|
|
@@ -1316,7 +1364,7 @@ function computeTextOverflows(cellGrid, rowPage, colGroup, visibleRows, visibleC
|
|
|
1316
1364
|
* Build rich text runs from a RichText cell.
|
|
1317
1365
|
* Returns null for non-RichText cells.
|
|
1318
1366
|
*/
|
|
1319
|
-
function buildRichTextRuns(cell, options, fontManager, scaleFactor) {
|
|
1367
|
+
function buildRichTextRuns(cell, options, fontManager, scaleFactor, cellFont) {
|
|
1320
1368
|
if (!cell || cell.type !== PdfCellType.RichText) {
|
|
1321
1369
|
return null;
|
|
1322
1370
|
}
|
|
@@ -1328,8 +1376,25 @@ function buildRichTextRuns(cell, options, fontManager, scaleFactor) {
|
|
|
1328
1376
|
if (runs.length === 0) {
|
|
1329
1377
|
return null;
|
|
1330
1378
|
}
|
|
1379
|
+
// Use cell-level font as fallback for runs without their own font,
|
|
1380
|
+
// falling back to global defaults only if cell font is not available.
|
|
1381
|
+
const defaultFamily = cellFont?.name ?? options.defaultFontFamily;
|
|
1382
|
+
const defaultSize = cellFont?.size ?? options.defaultFontSize;
|
|
1331
1383
|
return runs.map(run => {
|
|
1332
|
-
|
|
1384
|
+
// When a run has no font at all, use cell font entirely.
|
|
1385
|
+
// When a run has a partial font, merge with cell font for missing properties.
|
|
1386
|
+
const effectiveFont = run.font
|
|
1387
|
+
? {
|
|
1388
|
+
name: run.font.name ?? cellFont?.name,
|
|
1389
|
+
size: run.font.size ?? cellFont?.size,
|
|
1390
|
+
bold: run.font.bold ?? cellFont?.bold,
|
|
1391
|
+
italic: run.font.italic ?? cellFont?.italic,
|
|
1392
|
+
strike: run.font.strike ?? cellFont?.strike,
|
|
1393
|
+
underline: run.font.underline ?? cellFont?.underline,
|
|
1394
|
+
color: run.font.color ?? cellFont?.color
|
|
1395
|
+
}
|
|
1396
|
+
: cellFont;
|
|
1397
|
+
const fontProps = extractFontProperties(effectiveFont, defaultFamily, defaultSize);
|
|
1333
1398
|
// Register font for this run
|
|
1334
1399
|
if (fontManager.hasEmbeddedFont()) {
|
|
1335
1400
|
fontManager.trackText(run.text);
|
|
@@ -50,7 +50,7 @@ export function argbToPdfColor(argb) {
|
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Convert a color data object to PDF color.
|
|
53
|
-
* Handles
|
|
53
|
+
* Handles ARGB, theme-based, and indexed colors.
|
|
54
54
|
*/
|
|
55
55
|
export function excelColorToPdf(color) {
|
|
56
56
|
if (!color) {
|
|
@@ -72,6 +72,10 @@ export function excelColorToPdf(color) {
|
|
|
72
72
|
}
|
|
73
73
|
return base;
|
|
74
74
|
}
|
|
75
|
+
// Indexed colors (legacy Excel color palette)
|
|
76
|
+
if (color.indexed !== undefined) {
|
|
77
|
+
return indexedColorToPdf(color.indexed);
|
|
78
|
+
}
|
|
75
79
|
return null;
|
|
76
80
|
}
|
|
77
81
|
/**
|
|
@@ -97,6 +101,99 @@ function themeColorToPdf(themeIndex) {
|
|
|
97
101
|
}
|
|
98
102
|
return null;
|
|
99
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Standard Excel indexed color palette (56 colors + system colors).
|
|
106
|
+
* Index 0–7: legacy base colors
|
|
107
|
+
* Index 8–63: standard palette (indices 8–63)
|
|
108
|
+
* Index 64: system foreground (black)
|
|
109
|
+
* Index 65: system background (white)
|
|
110
|
+
*
|
|
111
|
+
* @see ECMA-376 §18.8.27 — indexedColors
|
|
112
|
+
*/
|
|
113
|
+
const INDEXED_COLORS = [
|
|
114
|
+
// 0–7: legacy base colors (same as 8–15 but less commonly used directly)
|
|
115
|
+
"000000", // 0: Black
|
|
116
|
+
"FFFFFF", // 1: White
|
|
117
|
+
"FF0000", // 2: Red
|
|
118
|
+
"00FF00", // 3: Green
|
|
119
|
+
"0000FF", // 4: Blue
|
|
120
|
+
"FFFF00", // 5: Yellow
|
|
121
|
+
"FF00FF", // 6: Magenta
|
|
122
|
+
"00FFFF", // 7: Cyan
|
|
123
|
+
// 8–63: standard palette
|
|
124
|
+
"000000", // 8: Black
|
|
125
|
+
"FFFFFF", // 9: White
|
|
126
|
+
"FF0000", // 10: Red
|
|
127
|
+
"00FF00", // 11: Green
|
|
128
|
+
"0000FF", // 12: Blue
|
|
129
|
+
"FFFF00", // 13: Yellow
|
|
130
|
+
"FF00FF", // 14: Magenta
|
|
131
|
+
"00FFFF", // 15: Cyan
|
|
132
|
+
"800000", // 16: Dark Red
|
|
133
|
+
"008000", // 17: Dark Green
|
|
134
|
+
"000080", // 18: Dark Blue (Navy)
|
|
135
|
+
"808000", // 19: Dark Yellow (Olive)
|
|
136
|
+
"800080", // 20: Purple
|
|
137
|
+
"008080", // 21: Teal
|
|
138
|
+
"C0C0C0", // 22: Silver
|
|
139
|
+
"808080", // 23: Gray
|
|
140
|
+
"9999FF", // 24: Periwinkle
|
|
141
|
+
"993366", // 25: Plum
|
|
142
|
+
"FFFFCC", // 26: Ivory
|
|
143
|
+
"CCFFFF", // 27: Light Cyan
|
|
144
|
+
"660066", // 28: Dark Purple
|
|
145
|
+
"FF8080", // 29: Coral
|
|
146
|
+
"0066CC", // 30: Ocean Blue
|
|
147
|
+
"CCCCFF", // 31: Ice Blue
|
|
148
|
+
"000080", // 32: Dark Blue
|
|
149
|
+
"FF00FF", // 33: Pink
|
|
150
|
+
"FFFF00", // 34: Yellow
|
|
151
|
+
"00FFFF", // 35: Cyan
|
|
152
|
+
"800080", // 36: Purple
|
|
153
|
+
"800000", // 37: Dark Red
|
|
154
|
+
"008080", // 38: Teal
|
|
155
|
+
"0000FF", // 39: Blue
|
|
156
|
+
"00CCFF", // 40: Sky Blue
|
|
157
|
+
"CCFFFF", // 41: Light Turquoise
|
|
158
|
+
"CCFFCC", // 42: Light Green
|
|
159
|
+
"FFFF99", // 43: Light Yellow
|
|
160
|
+
"99CCFF", // 44: Pale Blue
|
|
161
|
+
"FF99CC", // 45: Rose
|
|
162
|
+
"CC99FF", // 46: Lavender
|
|
163
|
+
"FFCC99", // 47: Tan
|
|
164
|
+
"3366FF", // 48: Light Blue
|
|
165
|
+
"33CCCC", // 49: Aqua
|
|
166
|
+
"99CC00", // 50: Lime
|
|
167
|
+
"FFCC00", // 51: Gold
|
|
168
|
+
"FF9900", // 52: Light Orange
|
|
169
|
+
"FF6600", // 53: Orange
|
|
170
|
+
"666699", // 54: Blue Gray
|
|
171
|
+
"969696", // 55: Gray 40%
|
|
172
|
+
"003366", // 56: Dark Teal
|
|
173
|
+
"339966", // 57: Sea Green
|
|
174
|
+
"003300", // 58: Very Dark Green
|
|
175
|
+
"333300", // 59: Dark Olive
|
|
176
|
+
"993300", // 60: Brown
|
|
177
|
+
"993366", // 61: Plum
|
|
178
|
+
"333399", // 62: Indigo
|
|
179
|
+
"333333" // 63: Gray 80%
|
|
180
|
+
];
|
|
181
|
+
/**
|
|
182
|
+
* Convert an indexed color to PDF color.
|
|
183
|
+
* Index 64 = system foreground (black), 65 = system background (white).
|
|
184
|
+
*/
|
|
185
|
+
function indexedColorToPdf(index) {
|
|
186
|
+
if (index === 64) {
|
|
187
|
+
return { r: 0, g: 0, b: 0 }; // System foreground (black)
|
|
188
|
+
}
|
|
189
|
+
if (index === 65) {
|
|
190
|
+
return { r: 1, g: 1, b: 1 }; // System background (white)
|
|
191
|
+
}
|
|
192
|
+
if (index >= 0 && index < INDEXED_COLORS.length) {
|
|
193
|
+
return argbToPdfColor(INDEXED_COLORS[index]) ?? null;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
100
197
|
/**
|
|
101
198
|
* Apply a tint value to a color.
|
|
102
199
|
* Tint range: -1.0 (fully dark) to +1.0 (fully light).
|