@segnavia/idml 0.38.0 → 0.39.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/dist/asset-from-placement.d.ts +7 -0
- package/dist/asset-from-placement.js +21 -0
- package/dist/import.d.ts +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/map-book.js +5 -2
- package/dist/model.d.ts +1 -1
- package/dist/stories.js +61 -15
- package/dist/styles.js +33 -6
- package/dist/table-html.js +49 -0
- package/dist/table-model.js +71 -0
- package/dist/table-styles.js +246 -0
- package/dist/types.d.ts +1 -1
- package/dist/unsupported-elements.js +7 -1
- package/package.json +3 -3
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IdmlAssetMap } from "./types.js";
|
|
2
|
+
import { ResolvePlacement } from "@segnavia/html";
|
|
3
|
+
//#region src/asset-from-placement.d.ts
|
|
4
|
+
export declare function idmlAssetFrom<R extends {
|
|
5
|
+
kind: string;
|
|
6
|
+
}>(resolve: ResolvePlacement<R>, uris: Iterable<string>, context: Parameters<ResolvePlacement<R>>[1]): Promise<IdmlAssetMap>;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { classifyMediaAnswer } from "@segnavia/html";
|
|
2
|
+
//#region src/asset-from-placement.ts
|
|
3
|
+
function escapeAttribute(value) {
|
|
4
|
+
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
5
|
+
}
|
|
6
|
+
async function idmlAssetFrom(resolve, uris, context) {
|
|
7
|
+
const entries = await Promise.all([...new Set(uris)].map(async (uri) => {
|
|
8
|
+
const answer = await resolve({
|
|
9
|
+
kind: "media",
|
|
10
|
+
address: uri
|
|
11
|
+
}, context);
|
|
12
|
+
const classified = classifyMediaAnswer({ answer });
|
|
13
|
+
if (classified.status !== "ok") return [uri, void 0];
|
|
14
|
+
const alt = classified.value.media.alt?.text ?? "";
|
|
15
|
+
return [uri, `<img src="${escapeAttribute(classified.value.src)}" alt="${escapeAttribute(alt)}">`];
|
|
16
|
+
}));
|
|
17
|
+
const resolved = new Map(entries);
|
|
18
|
+
return (uri) => resolved.get(uri);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { idmlAssetFrom };
|
package/dist/import.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IdmlReportData } from "./report.js";
|
|
2
1
|
import { IdmlImportOptions } from "./types.js";
|
|
2
|
+
import { IdmlReportData } from "./report.js";
|
|
3
3
|
import { Book } from "@segnavia/format";
|
|
4
4
|
//#region src/import.d.ts
|
|
5
5
|
export interface IdmlImportReport extends IdmlReportData {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { IdmlFontUse, IdmlLinkUse, IdmlReportData } from "./report.js";
|
|
2
1
|
import { IdmlAssetMap, IdmlDocumentPreferences, IdmlFont, IdmlFontMap, IdmlImportOptions, IdmlMargin, IdmlMasterSpread, IdmlPage, IdmlSpread, IdmlStory } from "./types.js";
|
|
2
|
+
import { idmlAssetFrom } from "./asset-from-placement.js";
|
|
3
|
+
import { IdmlFontUse, IdmlLinkUse, IdmlReportData } from "./report.js";
|
|
3
4
|
import { IDML_FONT_WEIGHTS, idmlFontStyle } from "./fonts.js";
|
|
4
5
|
import { IdmlImportReport, IdmlImportResult, importIdml } from "./import.js";
|
|
5
6
|
import { IDML_LIMITS, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH } from "./limits.js";
|
|
6
7
|
import { IdmlModel } from "./model.js";
|
|
7
|
-
export { IDML_FONT_WEIGHTS, IDML_LIMITS, type IdmlAssetMap, type IdmlDocumentPreferences, type IdmlFont, type IdmlFontMap, type IdmlFontUse, type IdmlImportOptions, type IdmlImportReport, type IdmlImportResult, type IdmlLinkUse, type IdmlMargin, type IdmlMasterSpread, type IdmlModel, type IdmlPage, type IdmlReportData, type IdmlSpread, type IdmlStory, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH, idmlFontStyle, importIdml };
|
|
8
|
+
export { IDML_FONT_WEIGHTS, IDML_LIMITS, type IdmlAssetMap, type IdmlDocumentPreferences, type IdmlFont, type IdmlFontMap, type IdmlFontUse, type IdmlImportOptions, type IdmlImportReport, type IdmlImportResult, type IdmlLinkUse, type IdmlMargin, type IdmlMasterSpread, type IdmlModel, type IdmlPage, type IdmlReportData, type IdmlSpread, type IdmlStory, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH, idmlAssetFrom, idmlFontStyle, importIdml };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import { idmlAssetFrom } from "./asset-from-placement.js";
|
|
1
2
|
import { IDML_FONT_WEIGHTS, idmlFontStyle } from "./fonts.js";
|
|
2
3
|
import { IDML_LIMITS, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH } from "./limits.js";
|
|
3
4
|
import { importIdml } from "./import.js";
|
|
4
|
-
export { IDML_FONT_WEIGHTS, IDML_LIMITS, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH, idmlFontStyle, importIdml };
|
|
5
|
+
export { IDML_FONT_WEIGHTS, IDML_LIMITS, MAX_IDML_ENTRIES, MAX_IDML_PACKAGE_BYTES, MAX_IDML_PART_BYTES, MAX_IDML_TOTAL_INFLATED_BYTES, MAX_IDML_XML_DEPTH, idmlAssetFrom, idmlFontStyle, importIdml };
|
package/dist/map-book.js
CHANGED
|
@@ -10,9 +10,10 @@ import { storyHtml } from "./stories.js";
|
|
|
10
10
|
import { chapterParents, mapMasters, openingPage, storyPageUses } from "./masters.js";
|
|
11
11
|
import { mapOpeners } from "./openers.js";
|
|
12
12
|
import { reportPlacements } from "./placement-report.js";
|
|
13
|
+
import { TableStyleMapper } from "./table-styles.js";
|
|
13
14
|
import { matchVariables } from "./variables.js";
|
|
14
|
-
import { Book, MM_PER_PT } from "@segnavia/format";
|
|
15
15
|
import { findActiveContent } from "@segnavia/html";
|
|
16
|
+
import { Book, MM_PER_PT } from "@segnavia/format";
|
|
16
17
|
//#region src/map-book.ts
|
|
17
18
|
function orderedStories(model, anchoredOnly = /* @__PURE__ */ new Set()) {
|
|
18
19
|
const order = /* @__PURE__ */ new Map();
|
|
@@ -52,6 +53,7 @@ function modelToBook(model, report = new ReportCollector(model.report), options
|
|
|
52
53
|
const bookDirection = rightBinding ? "rtl" : "ltr";
|
|
53
54
|
const fonts = new FontMapper(model.fonts ?? [], options.font, report);
|
|
54
55
|
const styles = new StyleMapper(model.styles ?? [], model.swatches ?? [], report, bookDirection, fonts);
|
|
56
|
+
const tableStyles = new TableStyleMapper(model.styles ?? [], model.swatches ?? [], report, (css) => styles.cssOverrideClass(css));
|
|
55
57
|
const matchedVariables = matchVariables(model.textVariables ?? [], report);
|
|
56
58
|
const bookLanguage = styles.rootLanguage();
|
|
57
59
|
const storyPages = storyPageUses(model);
|
|
@@ -64,6 +66,7 @@ function modelToBook(model, report = new ReportCollector(model.report), options
|
|
|
64
66
|
textVariables: matchedVariables,
|
|
65
67
|
master
|
|
66
68
|
}, styles, report, bookDirection, bookLanguage, {
|
|
69
|
+
tableStyles,
|
|
67
70
|
inlineParagraphs: depth > 0,
|
|
68
71
|
anchored: (location, direction) => {
|
|
69
72
|
const frame = frameByLocation.get(location);
|
|
@@ -117,7 +120,7 @@ function modelToBook(model, report = new ReportCollector(model.report), options
|
|
|
117
120
|
if (chapters.length === 0) throw refusal("the IDML has no stories", "add at least one Story");
|
|
118
121
|
refuseActiveBookHtml(chapters, masters.parents);
|
|
119
122
|
const columnGap = bodyColumnGap(model, stories, report);
|
|
120
|
-
const css = `${styles.css()}${masters.css}`;
|
|
123
|
+
const css = `${tableStyles.css()}${styles.css()}${masters.css}`;
|
|
121
124
|
const bookFonts = fonts.bookFonts();
|
|
122
125
|
return Book.parse({
|
|
123
126
|
title: model.id,
|
package/dist/model.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IdmlReportData } from "./report.js";
|
|
2
1
|
import { IdmlAnchoredFrame, IdmlDocumentPreferences, IdmlFont, IdmlFramePreference, IdmlMargin, IdmlMasterPage, IdmlMasterSpread, IdmlPage, IdmlSpread, IdmlStory, IdmlStyle, IdmlSwatch, IdmlTextVariable } from "./types.js";
|
|
2
|
+
import { IdmlReportData } from "./report.js";
|
|
3
3
|
//#region src/model.d.ts
|
|
4
4
|
export interface IdmlModel {
|
|
5
5
|
id: string;
|
package/dist/stories.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { tableNode } from "./table-html.js";
|
|
2
|
+
import { BOOK_COLUMN_MAX, BOOK_COLUMN_MIN } from "@segnavia/html";
|
|
1
3
|
import { BOOK_FURNITURE, MOTIF_ATTRIBUTE, motifFieldAttribute, resolveDirection } from "@segnavia/format";
|
|
2
4
|
import { Element, Text } from "domhandler";
|
|
3
|
-
import { BOOK_COLUMN_MAX, BOOK_COLUMN_MIN } from "@segnavia/html";
|
|
4
5
|
import serialize from "dom-serializer";
|
|
5
6
|
import { parseDocument } from "htmlparser2";
|
|
6
7
|
//#region src/stories.ts
|
|
@@ -8,7 +9,6 @@ const OMITTED = /* @__PURE__ */ new Set([
|
|
|
8
9
|
"Rectangle",
|
|
9
10
|
"Group",
|
|
10
11
|
"Polygon",
|
|
11
|
-
"Table",
|
|
12
12
|
"Footnote",
|
|
13
13
|
"Note"
|
|
14
14
|
]);
|
|
@@ -46,6 +46,11 @@ function tokens(root, report) {
|
|
|
46
46
|
character,
|
|
47
47
|
location: node.location
|
|
48
48
|
});
|
|
49
|
+
else if (node.name === "Table") result.push({
|
|
50
|
+
kind: "table",
|
|
51
|
+
node,
|
|
52
|
+
location: node.location
|
|
53
|
+
});
|
|
49
54
|
else if (node.name === "TextVariableInstance") result.push({
|
|
50
55
|
kind: "variable",
|
|
51
56
|
variable: node.attributes.AssociatedTextVariable,
|
|
@@ -58,8 +63,7 @@ function tokens(root, report) {
|
|
|
58
63
|
});
|
|
59
64
|
else if (OMITTED.has(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
60
65
|
else if (node.name === "Properties") return true;
|
|
61
|
-
else
|
|
62
|
-
else return false;
|
|
66
|
+
else return reportedChange(node, report);
|
|
63
67
|
return true;
|
|
64
68
|
};
|
|
65
69
|
const walk = (node, character) => {
|
|
@@ -86,6 +90,11 @@ function tokens(root, report) {
|
|
|
86
90
|
walk(root);
|
|
87
91
|
return result;
|
|
88
92
|
}
|
|
93
|
+
function reportedChange(node, report) {
|
|
94
|
+
if (node.name !== "Change" || node.attributes.ChangeType === void 0 || node.attributes.ChangeType.includes("Inserted")) return false;
|
|
95
|
+
report.add(report.unsupportedElements, "Change", node.location);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
89
98
|
function contentNodes(token, styles, direction) {
|
|
90
99
|
const character = token.character;
|
|
91
100
|
const characterAttributes = rangeAttributes(character);
|
|
@@ -205,6 +214,45 @@ function paragraphNode(paragraph, paragraphTokens, styles, report, bookDirection
|
|
|
205
214
|
style: "display:block"
|
|
206
215
|
} : htmlAttributes, children);
|
|
207
216
|
}
|
|
217
|
+
function mappedParagraph(paragraph, paragraphTokens, context, frame = context.story.frame) {
|
|
218
|
+
return paragraphNode(paragraph, paragraphTokens, context.styles, context.report, context.bookDirection, context.bookLanguage, context.story.direction, frame, context.story.textVariables ?? [], context.story.master ?? false, context.options);
|
|
219
|
+
}
|
|
220
|
+
function tableContent(cell, context) {
|
|
221
|
+
const output = [];
|
|
222
|
+
for (const paragraph of cell.children.filter((child) => child.name === "ParagraphStyleRange")) {
|
|
223
|
+
let current = [];
|
|
224
|
+
const flush = () => {
|
|
225
|
+
output.push(mappedParagraph(paragraph, current, context, void 0));
|
|
226
|
+
current = [];
|
|
227
|
+
};
|
|
228
|
+
for (const token of tokens(paragraph, context.report)) if (token.kind === "paragraph") flush();
|
|
229
|
+
else if (token.kind === "table") context.report.add(context.report.unsupportedElements, "Table", token.location);
|
|
230
|
+
else current.push(token);
|
|
231
|
+
flush();
|
|
232
|
+
}
|
|
233
|
+
return output;
|
|
234
|
+
}
|
|
235
|
+
function renderParagraphRange(paragraph, context) {
|
|
236
|
+
const output = [];
|
|
237
|
+
const all = tokens(paragraph, context.report);
|
|
238
|
+
let current = [];
|
|
239
|
+
let wroteTable = false;
|
|
240
|
+
const visible = () => current.some((token) => token.kind !== "text" || Boolean(token.text));
|
|
241
|
+
const flush = (empty = true) => {
|
|
242
|
+
if (empty || visible()) output.push(mappedParagraph(paragraph, current, context));
|
|
243
|
+
current = [];
|
|
244
|
+
};
|
|
245
|
+
for (const token of all) if (token.kind === "paragraph") flush();
|
|
246
|
+
else if (token.kind !== "table" || !token.node) current.push(token);
|
|
247
|
+
else {
|
|
248
|
+
flush(false);
|
|
249
|
+
if (!context.options.tableStyles) context.report.add(context.report.unsupportedElements, "Table", token.location);
|
|
250
|
+
else output.push(tableNode(token.node, context.options.tableStyles, (cell) => tableContent(cell, context)));
|
|
251
|
+
wroteTable = true;
|
|
252
|
+
}
|
|
253
|
+
if (visible() || !wroteTable && (all.length === 0 || all.at(-1)?.kind !== "paragraph")) flush();
|
|
254
|
+
return output;
|
|
255
|
+
}
|
|
208
256
|
function storyHtml(story, styles, report, bookDirection, bookLanguage, options = {}) {
|
|
209
257
|
if (!story.root) {
|
|
210
258
|
const empty = new Element(options.inlineParagraphs ? "span" : "p", options.inlineParagraphs ? { style: "display:block" } : {}, [new Element("br", {}, [])]);
|
|
@@ -220,17 +268,15 @@ function storyHtml(story, styles, report, bookDirection, bookLanguage, options =
|
|
|
220
268
|
else if (node.name === "Story" || node.name === "XMLElement") for (const child of node.children) collectParagraphs(child);
|
|
221
269
|
};
|
|
222
270
|
collectParagraphs(story.root);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (current.length > 0 || all.length === 0 || all.at(-1)?.kind !== "paragraph") flush();
|
|
233
|
-
}
|
|
271
|
+
const context = {
|
|
272
|
+
story,
|
|
273
|
+
styles,
|
|
274
|
+
report,
|
|
275
|
+
bookDirection,
|
|
276
|
+
bookLanguage,
|
|
277
|
+
options
|
|
278
|
+
};
|
|
279
|
+
for (const paragraph of paragraphRanges) paragraphs.push(...renderParagraphRange(paragraph, context));
|
|
234
280
|
if (paragraphs.length === 0) paragraphs.push(new Element(options.inlineParagraphs ? "span" : "p", options.inlineParagraphs ? { style: "display:block" } : {}, [new Element("br", {}, [])]));
|
|
235
281
|
return {
|
|
236
282
|
html: serialize(paragraphs, {
|
package/dist/styles.js
CHANGED
|
@@ -26,7 +26,9 @@ function parseStyles(roots, part) {
|
|
|
26
26
|
for (const kind of [
|
|
27
27
|
"ParagraphStyle",
|
|
28
28
|
"CharacterStyle",
|
|
29
|
-
"ObjectStyle"
|
|
29
|
+
"ObjectStyle",
|
|
30
|
+
"TableStyle",
|
|
31
|
+
"CellStyle"
|
|
30
32
|
]) for (const element of roots.filter((candidate) => localName(candidate.name) === kind)) {
|
|
31
33
|
const values = properties(element);
|
|
32
34
|
const id = values.Self;
|
|
@@ -34,7 +36,7 @@ function parseStyles(roots, part) {
|
|
|
34
36
|
result.push({
|
|
35
37
|
id,
|
|
36
38
|
name: values.Name ?? id.split("/").at(-1) ?? id,
|
|
37
|
-
kind: kind
|
|
39
|
+
kind: STYLE_KINDS[kind],
|
|
38
40
|
...values.BasedOn ? { basedOn: values.BasedOn } : {},
|
|
39
41
|
properties: Object.fromEntries(Object.entries(values).filter(([name]) => ![
|
|
40
42
|
"Self",
|
|
@@ -46,6 +48,13 @@ function parseStyles(roots, part) {
|
|
|
46
48
|
}
|
|
47
49
|
return result;
|
|
48
50
|
}
|
|
51
|
+
const STYLE_KINDS = {
|
|
52
|
+
ParagraphStyle: "paragraph",
|
|
53
|
+
CharacterStyle: "character",
|
|
54
|
+
ObjectStyle: "object",
|
|
55
|
+
TableStyle: "table",
|
|
56
|
+
CellStyle: "cell"
|
|
57
|
+
};
|
|
49
58
|
function parseSwatches(roots) {
|
|
50
59
|
const result = [];
|
|
51
60
|
for (const element of roots.filter((candidate) => localName(candidate.name) === "Color")) {
|
|
@@ -65,7 +74,11 @@ function parseSwatches(roots) {
|
|
|
65
74
|
return result;
|
|
66
75
|
}
|
|
67
76
|
function rootName(kind) {
|
|
68
|
-
|
|
77
|
+
if (kind === "paragraph") return PARAGRAPH_ROOT;
|
|
78
|
+
if (kind === "character") return CHARACTER_ROOT;
|
|
79
|
+
if (kind === "table") return "$ID/[No table style]";
|
|
80
|
+
if (kind === "cell") return "$ID/[None]";
|
|
81
|
+
return OBJECT_ROOT;
|
|
69
82
|
}
|
|
70
83
|
function findStyle(styles, id, kind) {
|
|
71
84
|
if (!id) return void 0;
|
|
@@ -147,6 +160,8 @@ var StyleMapper = class {
|
|
|
147
160
|
classes = /* @__PURE__ */ new Map();
|
|
148
161
|
used = /* @__PURE__ */ new Set();
|
|
149
162
|
overrides = /* @__PURE__ */ new Map();
|
|
163
|
+
rawOverrides = /* @__PURE__ */ new Map();
|
|
164
|
+
nextOverride = 1;
|
|
150
165
|
reportedStyleProperties = /* @__PURE__ */ new Set();
|
|
151
166
|
constructor(styles, swatches, report, bookDirection, fonts) {
|
|
152
167
|
this.swatches = swatches;
|
|
@@ -156,7 +171,7 @@ var StyleMapper = class {
|
|
|
156
171
|
this.byId = new Map(styles.map((style) => [style.id, style]));
|
|
157
172
|
const taken = /* @__PURE__ */ new Set();
|
|
158
173
|
for (const style of styles) {
|
|
159
|
-
if (style.kind === "object") continue;
|
|
174
|
+
if (style.kind === "object" || style.kind === "table" || style.kind === "cell") continue;
|
|
160
175
|
const base = `${style.kind === "paragraph" ? "idml-p-" : "idml-c-"}${slug(style.name)}`;
|
|
161
176
|
let candidate = base;
|
|
162
177
|
let suffix = 2;
|
|
@@ -198,7 +213,7 @@ var StyleMapper = class {
|
|
|
198
213
|
const key = JSON.stringify(Object.entries(cssProperties).sort(([a], [b]) => a.localeCompare(b))) + directionValue + resetShading;
|
|
199
214
|
const found = this.overrides.get(key);
|
|
200
215
|
if (found) return found.name;
|
|
201
|
-
const name = `idml-o-${this.
|
|
216
|
+
const name = `idml-o-${this.nextOverride++}`;
|
|
202
217
|
this.overrides.set(key, {
|
|
203
218
|
name,
|
|
204
219
|
properties: cssProperties,
|
|
@@ -208,6 +223,17 @@ var StyleMapper = class {
|
|
|
208
223
|
});
|
|
209
224
|
return name;
|
|
210
225
|
}
|
|
226
|
+
cssOverrideClass(declarations) {
|
|
227
|
+
if (!declarations) return void 0;
|
|
228
|
+
const found = this.rawOverrides.get(declarations);
|
|
229
|
+
if (found) return found.name;
|
|
230
|
+
const name = `idml-o-${this.nextOverride++}`;
|
|
231
|
+
this.rawOverrides.set(declarations, {
|
|
232
|
+
name,
|
|
233
|
+
declarations
|
|
234
|
+
});
|
|
235
|
+
return name;
|
|
236
|
+
}
|
|
211
237
|
paragraphDirection(properties) {
|
|
212
238
|
return idmlDirection(properties.ParagraphDirection);
|
|
213
239
|
}
|
|
@@ -241,6 +267,7 @@ var StyleMapper = class {
|
|
|
241
267
|
const declarations = this.declarations(value.properties, value.direction, value.location, this.report.unsupportedOverrideProperties, value.resetShading);
|
|
242
268
|
if (declarations) rules.push(`.${value.name}{${declarations}}`);
|
|
243
269
|
}
|
|
270
|
+
for (const value of this.rawOverrides.values()) rules.push(`.${value.name}{${value.declarations}}`);
|
|
244
271
|
return rules.join("");
|
|
245
272
|
}
|
|
246
273
|
declarations(values, dir, location, unsupported, resetShading) {
|
|
@@ -320,4 +347,4 @@ var StyleMapper = class {
|
|
|
320
347
|
}
|
|
321
348
|
};
|
|
322
349
|
//#endregion
|
|
323
|
-
export { StyleMapper, flattenedStyle, parseStyles, parseSwatches };
|
|
350
|
+
export { StyleMapper, flattenedStyle, parseStyles, parseSwatches, slug, styleChain };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { tableGrid } from "./table-model.js";
|
|
2
|
+
import { Element } from "domhandler";
|
|
3
|
+
import "dom-serializer";
|
|
4
|
+
//#region src/table-html.ts
|
|
5
|
+
function regionElement(region) {
|
|
6
|
+
return region === "header" ? "thead" : region === "footer" ? "tfoot" : "tbody";
|
|
7
|
+
}
|
|
8
|
+
function tableNode(node, styles, content) {
|
|
9
|
+
const grid = tableGrid(node);
|
|
10
|
+
const tableStyle = node.attributes.AppliedTableStyle;
|
|
11
|
+
const className = styles.tableClass(tableStyle);
|
|
12
|
+
const columns = new Element("colgroup", {}, grid.columns.map((width) => new Element("col", { style: `width:${width}pt` }, [])));
|
|
13
|
+
const groups = [];
|
|
14
|
+
let currentRegion;
|
|
15
|
+
let currentRows = [];
|
|
16
|
+
const flush = () => {
|
|
17
|
+
if (currentRegion && currentRows.length > 0) groups.push(new Element(regionElement(currentRegion), {}, currentRows));
|
|
18
|
+
currentRows = [];
|
|
19
|
+
};
|
|
20
|
+
for (const [rowIndex, row] of grid.rows.entries()) {
|
|
21
|
+
if (row.region !== currentRegion) {
|
|
22
|
+
flush();
|
|
23
|
+
currentRegion = row.region;
|
|
24
|
+
}
|
|
25
|
+
const cells = grid.cells.filter((cell) => cell.row === rowIndex);
|
|
26
|
+
currentRows.push(new Element("tr", row.fixed && row.height !== void 0 ? { style: `height:${row.height}pt` } : {}, cells.map((cell) => {
|
|
27
|
+
const classes = styles.cellClasses({
|
|
28
|
+
tableStyle,
|
|
29
|
+
region: row.region,
|
|
30
|
+
column: cell.column,
|
|
31
|
+
columnCount: grid.columns.length,
|
|
32
|
+
node: cell.node,
|
|
33
|
+
direction: grid.direction
|
|
34
|
+
});
|
|
35
|
+
return new Element("td", {
|
|
36
|
+
...cell.rowSpan > 1 ? { rowspan: String(cell.rowSpan) } : {},
|
|
37
|
+
...cell.columnSpan > 1 ? { colspan: String(cell.columnSpan) } : {},
|
|
38
|
+
...classes.length > 0 ? { class: classes.join(" ") } : {}
|
|
39
|
+
}, content(cell.node));
|
|
40
|
+
})));
|
|
41
|
+
}
|
|
42
|
+
flush();
|
|
43
|
+
return new Element("table", {
|
|
44
|
+
...className ? { class: className } : {},
|
|
45
|
+
dir: grid.direction
|
|
46
|
+
}, [columns, ...groups]);
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { tableNode };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { refusal } from "./refusal.js";
|
|
2
|
+
//#region src/table-model.ts
|
|
3
|
+
function integer(value, fallback) {
|
|
4
|
+
const parsed = Number(value);
|
|
5
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
6
|
+
}
|
|
7
|
+
function children(node, name) {
|
|
8
|
+
return node.children.filter((child) => child.name === name);
|
|
9
|
+
}
|
|
10
|
+
function cellLabel(node) {
|
|
11
|
+
return node.attributes.Name ?? node.location;
|
|
12
|
+
}
|
|
13
|
+
function placeCell(table, cell, occupied, rowCount, columnCount) {
|
|
14
|
+
const match = /^(\d+):(\d+)$/.exec(cell.attributes.Name ?? "");
|
|
15
|
+
const column = match ? Number(match[1]) : -1;
|
|
16
|
+
const row = match ? Number(match[2]) : -1;
|
|
17
|
+
const rowSpan = Math.max(1, integer(cell.attributes.RowSpan, 1));
|
|
18
|
+
const columnSpan = Math.max(1, integer(cell.attributes.ColumnSpan, 1));
|
|
19
|
+
if (row < 0 || column < 0 || row + rowSpan > rowCount || column + columnSpan > columnCount) throw refusal(`table at ${table.location} has cell ${cellLabel(cell)} outside the grid`, "give every Cell a Name inside the declared rows and columns");
|
|
20
|
+
for (let y = row; y < row + rowSpan; y += 1) {
|
|
21
|
+
const rowCells = occupied[y];
|
|
22
|
+
if (!rowCells) throw refusal(`table at ${table.location} has cell ${cellLabel(cell)} outside the grid`, "give every Cell a Name inside the declared rows");
|
|
23
|
+
for (let x = column; x < column + columnSpan; x += 1) {
|
|
24
|
+
const found = rowCells[x];
|
|
25
|
+
if (found) throw refusal(`table at ${table.location} has overlapping cells ${cellLabel(found)} and ${cellLabel(cell)}`, "remove the overlapping cell spans");
|
|
26
|
+
rowCells[x] = cell;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
row,
|
|
31
|
+
column,
|
|
32
|
+
rowSpan,
|
|
33
|
+
columnSpan,
|
|
34
|
+
node: cell
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function requireAnchors(table, occupied) {
|
|
38
|
+
for (const [row, columns] of occupied.entries()) for (const [column, cell] of columns.entries()) if (!cell) throw refusal(`table at ${table.location} has a missing anchor at ${column}:${row}`, "add a Cell that covers that grid position");
|
|
39
|
+
}
|
|
40
|
+
function tableGrid(node) {
|
|
41
|
+
const columns = children(node, "Column").map((column) => Number(column.attributes.SingleColumnWidth ?? column.attributes.Width));
|
|
42
|
+
const rowNodes = children(node, "Row");
|
|
43
|
+
const header = integer(node.attributes.HeaderRowCount, 0);
|
|
44
|
+
const footer = integer(node.attributes.FooterRowCount, 0);
|
|
45
|
+
const declaredBody = integer(node.attributes.BodyRowCount, rowNodes.length - header - footer);
|
|
46
|
+
const rowCount = header + declaredBody + footer;
|
|
47
|
+
const rows = rowNodes.map((row, index) => {
|
|
48
|
+
const height = Number(row.attributes.SingleRowHeight ?? row.attributes.Height);
|
|
49
|
+
return {
|
|
50
|
+
region: index < header ? "header" : index >= header + declaredBody ? "footer" : "body",
|
|
51
|
+
...Number.isFinite(height) ? { height } : {},
|
|
52
|
+
fixed: row.attributes.AutoGrow === "false"
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
const widthCount = columns.length || integer(node.attributes.ColumnCount, 0);
|
|
56
|
+
if (columns.some((width) => !Number.isFinite(width))) throw refusal(`table at ${node.location} has a column without a finite width`, "give every Column a numeric SingleColumnWidth or Width");
|
|
57
|
+
if (widthCount === 0) throw refusal(`table at ${node.location} has no columns`, "export at least one Column or declare a positive ColumnCount");
|
|
58
|
+
if (rowCount !== rows.length) throw refusal(`table at ${node.location} declares ${rowCount} rows but contains ${rows.length} Row elements`, "make HeaderRowCount, BodyRowCount, and FooterRowCount add up to the number of Row elements");
|
|
59
|
+
const occupied = Array.from({ length: rowCount }, () => Array.from({ length: widthCount }));
|
|
60
|
+
const cells = children(node, "Cell").map((cell) => placeCell(node, cell, occupied, rowCount, widthCount));
|
|
61
|
+
requireAnchors(node, occupied);
|
|
62
|
+
cells.sort((a, b) => a.row - b.row || a.column - b.column);
|
|
63
|
+
return {
|
|
64
|
+
direction: node.attributes.TableDirection === "RightToLeft" ? "rtl" : "ltr",
|
|
65
|
+
columns,
|
|
66
|
+
rows,
|
|
67
|
+
cells
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { tableGrid };
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { resolveSwatchColor } from "./swatch-color.js";
|
|
2
|
+
import { reportableStyleProperties } from "./style-property-report.js";
|
|
3
|
+
import { flattenedStyle, slug, styleChain } from "./styles.js";
|
|
4
|
+
//#region src/table-styles.ts
|
|
5
|
+
const TABLE_HANDLED = /* @__PURE__ */ new Set([
|
|
6
|
+
"SpaceBefore",
|
|
7
|
+
"SpaceAfter",
|
|
8
|
+
"HeaderRegionCellStyle",
|
|
9
|
+
"BodyRegionCellStyle",
|
|
10
|
+
"FooterRegionCellStyle",
|
|
11
|
+
"LeftColumnRegionCellStyle",
|
|
12
|
+
"RightColumnRegionCellStyle",
|
|
13
|
+
"AlternatingFills",
|
|
14
|
+
"StartRowFillColor",
|
|
15
|
+
"StartRowFillCount",
|
|
16
|
+
"EndRowFillColor",
|
|
17
|
+
"EndRowFillCount",
|
|
18
|
+
"SkipFirstAlternatingFillRows",
|
|
19
|
+
"SkipLastAlternatingFillRows",
|
|
20
|
+
"StartColumnFillColor",
|
|
21
|
+
"StartColumnFillCount",
|
|
22
|
+
"EndColumnFillColor",
|
|
23
|
+
"EndColumnFillCount",
|
|
24
|
+
"SkipFirstAlternatingFillColumns",
|
|
25
|
+
"SkipLastAlternatingFillColumns"
|
|
26
|
+
]);
|
|
27
|
+
const CELL_HANDLED = /* @__PURE__ */ new Set([
|
|
28
|
+
"AppliedCellStyle",
|
|
29
|
+
"FillColor",
|
|
30
|
+
"FillTint",
|
|
31
|
+
"VerticalJustification",
|
|
32
|
+
"TopInset",
|
|
33
|
+
"BottomInset",
|
|
34
|
+
"LeftInset",
|
|
35
|
+
"RightInset",
|
|
36
|
+
"TopEdgeStrokeWeight",
|
|
37
|
+
"BottomEdgeStrokeWeight",
|
|
38
|
+
"LeftEdgeStrokeWeight",
|
|
39
|
+
"RightEdgeStrokeWeight",
|
|
40
|
+
"TopEdgeStrokeColor",
|
|
41
|
+
"BottomEdgeStrokeColor",
|
|
42
|
+
"LeftEdgeStrokeColor",
|
|
43
|
+
"RightEdgeStrokeColor",
|
|
44
|
+
"TopEdgeStrokeType",
|
|
45
|
+
"BottomEdgeStrokeType",
|
|
46
|
+
"LeftEdgeStrokeType",
|
|
47
|
+
"RightEdgeStrokeType",
|
|
48
|
+
"CellType",
|
|
49
|
+
"TextRotation",
|
|
50
|
+
"DiagonalLineInFront",
|
|
51
|
+
"TopLeftDiagonalLine",
|
|
52
|
+
"TopRightDiagonalLine"
|
|
53
|
+
]);
|
|
54
|
+
function uniqueClasses(styles, kind, prefix) {
|
|
55
|
+
const result = /* @__PURE__ */ new Map();
|
|
56
|
+
const taken = /* @__PURE__ */ new Set();
|
|
57
|
+
for (const style of styles.filter((candidate) => candidate.kind === kind)) {
|
|
58
|
+
const base = `${prefix}${slug(style.name)}`;
|
|
59
|
+
let value = base;
|
|
60
|
+
let suffix = 2;
|
|
61
|
+
while (taken.has(value)) value = `${base}-${suffix++}`;
|
|
62
|
+
taken.add(value);
|
|
63
|
+
result.set(style.id, value);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
function tint(color, raw) {
|
|
68
|
+
const value = Number(raw);
|
|
69
|
+
return Number.isFinite(value) && value >= 0 && value < 100 ? `color-mix(in srgb, ${color} ${value}%, #fff)` : color;
|
|
70
|
+
}
|
|
71
|
+
function active(value) {
|
|
72
|
+
return value !== void 0 && ![
|
|
73
|
+
"",
|
|
74
|
+
"false",
|
|
75
|
+
"0",
|
|
76
|
+
"None",
|
|
77
|
+
"$ID/None"
|
|
78
|
+
].includes(value);
|
|
79
|
+
}
|
|
80
|
+
var TableStyleMapper = class {
|
|
81
|
+
styles;
|
|
82
|
+
swatches;
|
|
83
|
+
report;
|
|
84
|
+
overrideClass;
|
|
85
|
+
tableClasses;
|
|
86
|
+
cellClassesById;
|
|
87
|
+
usedTables = /* @__PURE__ */ new Set();
|
|
88
|
+
usedRegionCells = /* @__PURE__ */ new Set();
|
|
89
|
+
usedOwnCells = /* @__PURE__ */ new Set();
|
|
90
|
+
reported = /* @__PURE__ */ new Set();
|
|
91
|
+
constructor(styles, swatches, report, overrideClass) {
|
|
92
|
+
this.styles = styles;
|
|
93
|
+
this.swatches = swatches;
|
|
94
|
+
this.report = report;
|
|
95
|
+
this.overrideClass = overrideClass;
|
|
96
|
+
this.tableClasses = uniqueClasses(styles, "table", "idml-t-");
|
|
97
|
+
this.cellClassesById = uniqueClasses(styles, "cell", "idml-cell-");
|
|
98
|
+
}
|
|
99
|
+
tableClass(id) {
|
|
100
|
+
const style = this.find(id, "table");
|
|
101
|
+
if (!style) return void 0;
|
|
102
|
+
this.usedTables.add(style.id);
|
|
103
|
+
return this.tableClasses.get(style.id);
|
|
104
|
+
}
|
|
105
|
+
cellClasses(input) {
|
|
106
|
+
const table = flattenedStyle(this.styles, input.tableStyle, "table");
|
|
107
|
+
const regionProperty = `${input.region[0]?.toUpperCase()}${input.region.slice(1)}RegionCellStyle`;
|
|
108
|
+
const physicalFirst = input.direction === "rtl" ? input.columnCount - 1 : 0;
|
|
109
|
+
const physicalLast = input.direction === "rtl" ? 0 : input.columnCount - 1;
|
|
110
|
+
const regionIds = [
|
|
111
|
+
table[regionProperty],
|
|
112
|
+
input.column === physicalFirst ? table.LeftColumnRegionCellStyle : void 0,
|
|
113
|
+
input.column === physicalLast ? table.RightColumnRegionCellStyle : void 0
|
|
114
|
+
].filter((value) => Boolean(value));
|
|
115
|
+
const ownId = input.node.attributes.AppliedCellStyle;
|
|
116
|
+
const output = [];
|
|
117
|
+
for (const id of regionIds) {
|
|
118
|
+
const style = this.find(id, "cell");
|
|
119
|
+
if (!style) continue;
|
|
120
|
+
this.usedRegionCells.add(style.id);
|
|
121
|
+
const className = this.cellClassesById.get(style.id);
|
|
122
|
+
if (className) output.push(className);
|
|
123
|
+
}
|
|
124
|
+
if (ownId) {
|
|
125
|
+
const style = this.find(ownId, "cell");
|
|
126
|
+
if (style) {
|
|
127
|
+
this.usedOwnCells.add(style.id);
|
|
128
|
+
const className = this.cellClassesById.get(style.id);
|
|
129
|
+
if (className) output.push(className);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const ids = [...regionIds, ownId].filter((value) => Boolean(value));
|
|
133
|
+
const base = Object.assign({}, ...ids.map((id) => flattenedStyle(this.styles, id, "cell")));
|
|
134
|
+
const local = Object.fromEntries(Object.entries(input.node.attributes).filter(([name, value]) => CELL_HANDLED.has(name) && name !== "AppliedCellStyle" && value !== base[name]));
|
|
135
|
+
const override = this.overrideClass(this.cellDeclarations(local, input.node.location));
|
|
136
|
+
if (override) output.push(override);
|
|
137
|
+
this.reportFeatures(input.node);
|
|
138
|
+
return output;
|
|
139
|
+
}
|
|
140
|
+
css() {
|
|
141
|
+
const rules = [];
|
|
142
|
+
for (const id of this.usedTables) {
|
|
143
|
+
const style = this.find(id, "table");
|
|
144
|
+
const className = style && this.tableClasses.get(style.id);
|
|
145
|
+
if (!style || !className) continue;
|
|
146
|
+
const values = flattenedStyle(this.styles, id, "table");
|
|
147
|
+
const declarations = [`border-collapse:collapse`];
|
|
148
|
+
const before = Number(values.SpaceBefore);
|
|
149
|
+
const after = Number(values.SpaceAfter);
|
|
150
|
+
if (Number.isFinite(before)) declarations.push(`margin-block-start:${before}pt`);
|
|
151
|
+
if (Number.isFinite(after)) declarations.push(`margin-block-end:${after}pt`);
|
|
152
|
+
rules.push(`.${className}{${declarations.join(";")}}`, ...this.alternatingRules(className, values, style.location));
|
|
153
|
+
this.reportUnmapped(style, TABLE_HANDLED);
|
|
154
|
+
}
|
|
155
|
+
for (const id of [...this.usedRegionCells, ...this.usedOwnCells]) {
|
|
156
|
+
const style = this.find(id, "cell");
|
|
157
|
+
const className = style && this.cellClassesById.get(style.id);
|
|
158
|
+
if (!style || !className) continue;
|
|
159
|
+
rules.push(`.${className}{${this.cellDeclarations(flattenedStyle(this.styles, id, "cell"), style.location)}}`);
|
|
160
|
+
this.reportUnmapped(style, CELL_HANDLED);
|
|
161
|
+
}
|
|
162
|
+
return rules.join("");
|
|
163
|
+
}
|
|
164
|
+
find(id, kind) {
|
|
165
|
+
if (!id) return void 0;
|
|
166
|
+
return this.styles.find((style) => style.kind === kind && (style.id === id || style.name === id || style.id.endsWith(`/${id}`)));
|
|
167
|
+
}
|
|
168
|
+
reportUnmapped(style, handled) {
|
|
169
|
+
const resolved = {};
|
|
170
|
+
for (const source of styleChain(this.styles, style.id, style.kind)) {
|
|
171
|
+
Object.assign(resolved, source.properties);
|
|
172
|
+
for (const property of reportableStyleProperties(source.properties, resolved).filter((name) => !handled.has(name))) {
|
|
173
|
+
const key = `${source.id}\0${property}`;
|
|
174
|
+
if (this.reported.has(key)) continue;
|
|
175
|
+
this.reported.add(key);
|
|
176
|
+
this.report.add(this.report.unsupportedStyleProperties, property, source.location);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
reportFeatures(node) {
|
|
181
|
+
if (node.attributes.CellType === "GraphicTypeCell") this.report.add(this.report.unsupportedElements, "Table:GraphicCell", node.location);
|
|
182
|
+
if (active(node.attributes.TextRotation)) this.report.add(this.report.unsupportedElements, "Table:RotatedCell", node.location);
|
|
183
|
+
if (active(node.attributes.DiagonalLineInFront) || active(node.attributes.TopLeftDiagonalLine) || active(node.attributes.TopRightDiagonalLine)) this.report.add(this.report.unsupportedElements, "Table:DiagonalLine", node.location);
|
|
184
|
+
}
|
|
185
|
+
cellDeclarations(values, location) {
|
|
186
|
+
const output = [];
|
|
187
|
+
const edge = (name) => {
|
|
188
|
+
const logical = name === "Top" ? "block-start" : name === "Bottom" ? "block-end" : name === "Left" ? "inline-start" : "inline-end";
|
|
189
|
+
const weight = Number(values[`${name}EdgeStrokeWeight`]);
|
|
190
|
+
if (Number.isFinite(weight)) output.push(`border-${logical}-width:${weight}pt`);
|
|
191
|
+
const type = values[`${name}EdgeStrokeType`];
|
|
192
|
+
if (type) {
|
|
193
|
+
const normalized = type.replace(/^\$ID\//, "").toLowerCase();
|
|
194
|
+
if ([
|
|
195
|
+
"solid",
|
|
196
|
+
"dashed",
|
|
197
|
+
"dotted"
|
|
198
|
+
].includes(normalized)) output.push(`border-${logical}-style:${normalized}`);
|
|
199
|
+
else this.report.add(this.report.unsupportedElements, `Table:StrokeType:${type}`, location);
|
|
200
|
+
}
|
|
201
|
+
const color = resolveSwatchColor(values[`${name}EdgeStrokeColor`], this.swatches, this.report, location, "fill", `${name}EdgeStrokeColor`);
|
|
202
|
+
if (color && color !== "none") output.push(`border-${logical}-color:${color}`);
|
|
203
|
+
};
|
|
204
|
+
for (const name of [
|
|
205
|
+
"Top",
|
|
206
|
+
"Bottom",
|
|
207
|
+
"Left",
|
|
208
|
+
"Right"
|
|
209
|
+
]) edge(name);
|
|
210
|
+
for (const [name, property] of [
|
|
211
|
+
["TopInset", "block-start"],
|
|
212
|
+
["BottomInset", "block-end"],
|
|
213
|
+
["LeftInset", "inline-start"],
|
|
214
|
+
["RightInset", "inline-end"]
|
|
215
|
+
]) {
|
|
216
|
+
const value = Number(values[name]);
|
|
217
|
+
if (Number.isFinite(value)) output.push(`padding-${property}:${value}pt`);
|
|
218
|
+
}
|
|
219
|
+
const fill = resolveSwatchColor(values.FillColor, this.swatches, this.report, location, "fill");
|
|
220
|
+
if (fill && fill !== "none") output.push(`background-color:${tint(fill, values.FillTint)}`);
|
|
221
|
+
const vertical = values.VerticalJustification?.replace(/^\$ID\//, "").toLowerCase();
|
|
222
|
+
if (vertical === "topalign" || vertical === "top") output.push("vertical-align:top");
|
|
223
|
+
else if (vertical === "centeralign" || vertical === "center") output.push("vertical-align:middle");
|
|
224
|
+
else if (vertical === "bottomalign" || vertical === "bottom") output.push("vertical-align:bottom");
|
|
225
|
+
else if (vertical && vertical !== "none") this.report.add(this.report.unsupportedElements, "Table:VerticalJustify", location);
|
|
226
|
+
return output.join(";");
|
|
227
|
+
}
|
|
228
|
+
alternatingRules(className, values, location) {
|
|
229
|
+
const axis = values.AlternatingFills?.includes("Column") ? "Column" : values.AlternatingFills?.includes("Row") ? "Row" : void 0;
|
|
230
|
+
if (!axis) return [];
|
|
231
|
+
const a = Math.max(0, Number(values[`Start${axis}FillCount`]) || 0);
|
|
232
|
+
const period = a + Math.max(0, Number(values[`End${axis}FillCount`]) || 0);
|
|
233
|
+
if (period === 0) return [];
|
|
234
|
+
const selector = axis === "Row" ? "tr" : "td";
|
|
235
|
+
const skip = Math.max(0, Number(values[`SkipFirstAlternatingFill${axis}s`]) || 0);
|
|
236
|
+
const colors = [values[`Start${axis}FillColor`], values[`End${axis}FillColor`]];
|
|
237
|
+
const rules = [];
|
|
238
|
+
for (let index = 0; index < period; index += 1) {
|
|
239
|
+
const color = resolveSwatchColor(colors[index < a ? 0 : 1], this.swatches, this.report, location, "fill");
|
|
240
|
+
if (color && color !== "none") rules.push(`.${className} ${selector}:nth-child(${period}n+${skip + index + 1}){background-color:${color}}`);
|
|
241
|
+
}
|
|
242
|
+
return rules;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
//#endregion
|
|
246
|
+
export { TableStyleMapper };
|
package/dist/types.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface IdmlTextNode {
|
|
|
10
10
|
export interface IdmlStyle {
|
|
11
11
|
id: string;
|
|
12
12
|
name: string;
|
|
13
|
-
kind: 'paragraph' | 'character' | 'object';
|
|
13
|
+
kind: 'paragraph' | 'character' | 'object' | 'table' | 'cell';
|
|
14
14
|
basedOn?: string;
|
|
15
15
|
properties: Record<string, string>;
|
|
16
16
|
location: string;
|
|
@@ -37,8 +37,14 @@ const MAPPED_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
37
37
|
"ParagraphStyleGroup",
|
|
38
38
|
"RootCharacterStyleGroup",
|
|
39
39
|
"CharacterStyleGroup",
|
|
40
|
+
"RootTableStyleGroup",
|
|
41
|
+
"TableStyleGroup",
|
|
42
|
+
"RootCellStyleGroup",
|
|
43
|
+
"CellStyleGroup",
|
|
40
44
|
"ParagraphStyle",
|
|
41
45
|
"CharacterStyle",
|
|
46
|
+
"TableStyle",
|
|
47
|
+
"CellStyle",
|
|
42
48
|
"AnchoredObjectSetting",
|
|
43
49
|
"Color",
|
|
44
50
|
"TextVariable",
|
|
@@ -49,7 +55,7 @@ function insideMappedResource(element) {
|
|
|
49
55
|
let parent = element.parent;
|
|
50
56
|
while (parent && "name" in parent) {
|
|
51
57
|
const name = localName(parent.name);
|
|
52
|
-
if (name === "ParagraphStyle" || name === "CharacterStyle" || name === "ObjectStyle" || name === "Color") return true;
|
|
58
|
+
if (name === "ParagraphStyle" || name === "CharacterStyle" || name === "ObjectStyle" || name === "TableStyle" || name === "CellStyle" || name === "Color") return true;
|
|
53
59
|
parent = parent.parent;
|
|
54
60
|
}
|
|
55
61
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segnavia/idml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@segnavia/format": "0.
|
|
30
|
-
"@segnavia/html": "0.
|
|
29
|
+
"@segnavia/format": "0.39.0",
|
|
30
|
+
"@segnavia/html": "0.39.0",
|
|
31
31
|
"dom-serializer": "^2.0.0",
|
|
32
32
|
"domhandler": "^5.0.3",
|
|
33
33
|
"htmlparser2": "^10.0.0"
|