@json-to-office/core-docx 0.15.0 → 0.16.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/components/highcharts.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/visual.d.ts +42 -0
- package/dist/components/visual.d.ts.map +1 -0
- package/dist/core/cached-render.d.ts.map +1 -1
- package/dist/core/flattenVisuals.d.ts +33 -0
- package/dist/core/flattenVisuals.d.ts.map +1 -0
- package/dist/core/render.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +291 -29
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +176 -29
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/styles/utils/componentDefaults.d.ts +6 -0
- package/dist/styles/utils/componentDefaults.d.ts.map +1 -1
- package/dist/styles/utils/resolveComponentTree.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/serviceClient.d.ts +39 -0
- package/dist/utils/serviceClient.d.ts.map +1 -0
- package/package.json +3 -3
|
@@ -2038,7 +2038,8 @@ import {
|
|
|
2038
2038
|
isTableComponent,
|
|
2039
2039
|
isListComponent,
|
|
2040
2040
|
isTocComponent,
|
|
2041
|
-
isHighchartsComponent
|
|
2041
|
+
isHighchartsComponent,
|
|
2042
|
+
isVisualComponent
|
|
2042
2043
|
} from "@json-to-office/shared-docx";
|
|
2043
2044
|
|
|
2044
2045
|
// src/utils/formatters.ts
|
|
@@ -2131,6 +2132,9 @@ function resolveListProps(props, theme) {
|
|
|
2131
2132
|
function resolveHighchartsProps(props, _theme) {
|
|
2132
2133
|
return props;
|
|
2133
2134
|
}
|
|
2135
|
+
function resolveVisualProps(props, _theme) {
|
|
2136
|
+
return props;
|
|
2137
|
+
}
|
|
2134
2138
|
function getCustomComponentDefaults(theme, componentName) {
|
|
2135
2139
|
const defaults = getComponentDefaults(theme);
|
|
2136
2140
|
return defaults?.[componentName] || {};
|
|
@@ -2160,7 +2164,8 @@ var RESOLVER_MAP = {
|
|
|
2160
2164
|
section: resolveSectionProps,
|
|
2161
2165
|
columns: resolveColumnsProps,
|
|
2162
2166
|
list: resolveListProps,
|
|
2163
|
-
highcharts: resolveHighchartsProps
|
|
2167
|
+
highcharts: resolveHighchartsProps,
|
|
2168
|
+
visual: resolveVisualProps
|
|
2164
2169
|
};
|
|
2165
2170
|
function resolveComponentDefaults(component, theme) {
|
|
2166
2171
|
if (!component.props) return component;
|
|
@@ -4141,7 +4146,7 @@ function initializeComponentCache(cache) {
|
|
|
4141
4146
|
}
|
|
4142
4147
|
}
|
|
4143
4148
|
async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
|
|
4144
|
-
const forceBypassForType = component.name === "toc" || component.name === "section" || componentHasRevision(component);
|
|
4149
|
+
const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || componentHasRevision(component);
|
|
4145
4150
|
if (!componentCache) {
|
|
4146
4151
|
initializeComponentCache();
|
|
4147
4152
|
}
|
|
@@ -6393,21 +6398,61 @@ function isNodeEnvironment() {
|
|
|
6393
6398
|
return typeof process !== "undefined" && process.versions != null && process.versions.node != null && typeof process.versions.node === "string";
|
|
6394
6399
|
}
|
|
6395
6400
|
|
|
6401
|
+
// src/utils/serviceClient.ts
|
|
6402
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
6403
|
+
function resolveServiceUrl(propsUrl, servicesUrl, defaultUrl) {
|
|
6404
|
+
const raw = (propsUrl || servicesUrl || defaultUrl).trim();
|
|
6405
|
+
const withScheme = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
|
|
6406
|
+
return withScheme.replace(/\/+$/, "");
|
|
6407
|
+
}
|
|
6408
|
+
async function postJsonToService(opts) {
|
|
6409
|
+
const resolvedHeaders = typeof opts.headers === "function" ? await opts.headers(opts.body) : opts.headers;
|
|
6410
|
+
const headers = {
|
|
6411
|
+
"Content-Type": "application/json",
|
|
6412
|
+
...resolvedHeaders
|
|
6413
|
+
};
|
|
6414
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
6415
|
+
const controller = new AbortController();
|
|
6416
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6417
|
+
let response;
|
|
6418
|
+
try {
|
|
6419
|
+
response = await fetch(`${opts.url}${opts.path}`, {
|
|
6420
|
+
method: "POST",
|
|
6421
|
+
headers,
|
|
6422
|
+
body: JSON.stringify(opts.body),
|
|
6423
|
+
signal: controller.signal
|
|
6424
|
+
});
|
|
6425
|
+
} catch (error) {
|
|
6426
|
+
if (error?.name === "AbortError") {
|
|
6427
|
+
throw new Error(
|
|
6428
|
+
`${opts.serviceLabel} timed out after ${timeoutMs}ms at ${opts.url}.`
|
|
6429
|
+
);
|
|
6430
|
+
}
|
|
6431
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
6432
|
+
throw new Error(opts.onUnreachable(opts.url, cause));
|
|
6433
|
+
} finally {
|
|
6434
|
+
clearTimeout(timer);
|
|
6435
|
+
}
|
|
6436
|
+
if (!response.ok) {
|
|
6437
|
+
throw new Error(
|
|
6438
|
+
`${opts.serviceLabel} returned ${response.status}: ${response.statusText}`
|
|
6439
|
+
);
|
|
6440
|
+
}
|
|
6441
|
+
return response;
|
|
6442
|
+
}
|
|
6443
|
+
|
|
6396
6444
|
// src/components/highcharts.ts
|
|
6397
6445
|
var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
|
|
6398
|
-
function getExportServerUrl(propsUrl, servicesUrl) {
|
|
6399
|
-
const raw = propsUrl || servicesUrl || DEFAULT_EXPORT_SERVER_URL;
|
|
6400
|
-
return raw.startsWith("http") ? raw : `http://${raw}`;
|
|
6401
|
-
}
|
|
6402
6446
|
async function generateChart(config, servicesConfig) {
|
|
6403
6447
|
if (!isNodeEnvironment()) {
|
|
6404
6448
|
throw new Error(
|
|
6405
6449
|
"Highcharts export server requires a Node.js environment. Chart generation is not available in browser environments."
|
|
6406
6450
|
);
|
|
6407
6451
|
}
|
|
6408
|
-
const serverUrl =
|
|
6452
|
+
const serverUrl = resolveServiceUrl(
|
|
6409
6453
|
config.serverUrl,
|
|
6410
|
-
servicesConfig?.serverUrl
|
|
6454
|
+
servicesConfig?.serverUrl,
|
|
6455
|
+
DEFAULT_EXPORT_SERVER_URL
|
|
6411
6456
|
);
|
|
6412
6457
|
const requestBody = {
|
|
6413
6458
|
infile: config.options,
|
|
@@ -6415,26 +6460,15 @@ async function generateChart(config, servicesConfig) {
|
|
|
6415
6460
|
b64: true,
|
|
6416
6461
|
scale: config.scale
|
|
6417
6462
|
};
|
|
6418
|
-
const
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
body: JSON.stringify(requestBody)
|
|
6427
|
-
}).catch((error) => {
|
|
6428
|
-
throw new Error(
|
|
6429
|
-
`Highcharts Export Server is not running at ${serverUrl}. Start it with: npx highcharts-export-server --enableServer true
|
|
6430
|
-
Cause: ${error instanceof Error ? error.message : String(error)}`
|
|
6431
|
-
);
|
|
6463
|
+
const response = await postJsonToService({
|
|
6464
|
+
url: serverUrl,
|
|
6465
|
+
path: "/export",
|
|
6466
|
+
body: requestBody,
|
|
6467
|
+
headers: servicesConfig?.headers,
|
|
6468
|
+
serviceLabel: "Highcharts export server",
|
|
6469
|
+
onUnreachable: (url, cause) => `Highcharts Export Server is not running at ${url}. Start it with: npx highcharts-export-server --enableServer true
|
|
6470
|
+
Cause: ${cause}`
|
|
6432
6471
|
});
|
|
6433
|
-
if (!response.ok) {
|
|
6434
|
-
throw new Error(
|
|
6435
|
-
`Highcharts export server returned ${response.status}: ${response.statusText}`
|
|
6436
|
-
);
|
|
6437
|
-
}
|
|
6438
6472
|
const base64Data = await response.text();
|
|
6439
6473
|
const base64DataUri = `data:image/png;base64,${base64Data}`;
|
|
6440
6474
|
const width = config.options.chart.width;
|
|
@@ -6468,6 +6502,109 @@ async function renderHighchartsComponent(component, theme, themeName, context) {
|
|
|
6468
6502
|
return imageParagraphs;
|
|
6469
6503
|
}
|
|
6470
6504
|
|
|
6505
|
+
// src/components/visual.ts
|
|
6506
|
+
import {
|
|
6507
|
+
clampVisualDpi,
|
|
6508
|
+
DEFAULT_VISUAL_DPI
|
|
6509
|
+
} from "@json-to-office/shared";
|
|
6510
|
+
var DEFAULT_RASTERIZE_SERVER_URL = "http://localhost:7802";
|
|
6511
|
+
var PIXELS_PER_INCH = 96;
|
|
6512
|
+
function buildVisualPresentation(props) {
|
|
6513
|
+
const { canvas, elements } = props;
|
|
6514
|
+
const presentationProps = {
|
|
6515
|
+
slideWidth: canvas.width,
|
|
6516
|
+
slideHeight: canvas.height
|
|
6517
|
+
};
|
|
6518
|
+
if (canvas.theme) presentationProps.theme = canvas.theme;
|
|
6519
|
+
const slideProps = {};
|
|
6520
|
+
if (canvas.background) slideProps.background = canvas.background;
|
|
6521
|
+
return {
|
|
6522
|
+
name: "pptx",
|
|
6523
|
+
props: presentationProps,
|
|
6524
|
+
children: [
|
|
6525
|
+
{
|
|
6526
|
+
name: "slide",
|
|
6527
|
+
props: slideProps,
|
|
6528
|
+
children: elements ?? []
|
|
6529
|
+
}
|
|
6530
|
+
]
|
|
6531
|
+
};
|
|
6532
|
+
}
|
|
6533
|
+
function defaultVisualWidthPx(props) {
|
|
6534
|
+
return Math.round(props.canvas.width * PIXELS_PER_INCH);
|
|
6535
|
+
}
|
|
6536
|
+
function visualToImageOptions(props) {
|
|
6537
|
+
return {
|
|
6538
|
+
width: props.width ?? defaultVisualWidthPx(props),
|
|
6539
|
+
...props.height !== void 0 && { height: props.height },
|
|
6540
|
+
alignment: props.alignment ?? "center",
|
|
6541
|
+
...props.caption !== void 0 && { caption: props.caption },
|
|
6542
|
+
...props.spacing !== void 0 && { spacing: props.spacing },
|
|
6543
|
+
...props.floating !== void 0 && { floating: props.floating },
|
|
6544
|
+
...props.keepNext !== void 0 && { keepNext: props.keepNext },
|
|
6545
|
+
...props.keepLines !== void 0 && { keepLines: props.keepLines }
|
|
6546
|
+
};
|
|
6547
|
+
}
|
|
6548
|
+
async function rasterize(presentation, dpi, propsServerUrl, serviceConfig) {
|
|
6549
|
+
if (!isNodeEnvironment()) {
|
|
6550
|
+
throw new Error(
|
|
6551
|
+
"Visual rasterization requires a Node.js environment. It is not available in browser environments."
|
|
6552
|
+
);
|
|
6553
|
+
}
|
|
6554
|
+
if (serviceConfig?.render) {
|
|
6555
|
+
return serviceConfig.render({ presentation, dpi });
|
|
6556
|
+
}
|
|
6557
|
+
const serverUrl = resolveServiceUrl(
|
|
6558
|
+
propsServerUrl,
|
|
6559
|
+
serviceConfig?.serverUrl,
|
|
6560
|
+
DEFAULT_RASTERIZE_SERVER_URL
|
|
6561
|
+
);
|
|
6562
|
+
const response = await postJsonToService({
|
|
6563
|
+
url: serverUrl,
|
|
6564
|
+
path: "/rasterize",
|
|
6565
|
+
body: { presentation, dpi },
|
|
6566
|
+
headers: serviceConfig?.headers,
|
|
6567
|
+
serviceLabel: "PPTX rasterization service",
|
|
6568
|
+
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Configure services.pptx with a \`render\` callback or a running \`serverUrl\`.
|
|
6569
|
+
Cause: ${cause}`
|
|
6570
|
+
});
|
|
6571
|
+
let result;
|
|
6572
|
+
try {
|
|
6573
|
+
result = await response.json();
|
|
6574
|
+
} catch {
|
|
6575
|
+
throw new Error(
|
|
6576
|
+
"PPTX rasterization service returned a non-JSON response (expected { base64DataUri, width, height })."
|
|
6577
|
+
);
|
|
6578
|
+
}
|
|
6579
|
+
if (!result?.base64DataUri) {
|
|
6580
|
+
throw new Error(
|
|
6581
|
+
"PPTX rasterization service returned a malformed response (missing base64DataUri)."
|
|
6582
|
+
);
|
|
6583
|
+
}
|
|
6584
|
+
return result;
|
|
6585
|
+
}
|
|
6586
|
+
async function renderVisualComponent(component, theme, themeName, context) {
|
|
6587
|
+
if (!isVisualComponent(component)) return [];
|
|
6588
|
+
const props = component.props;
|
|
6589
|
+
const serviceConfig = context?.services?.pptx;
|
|
6590
|
+
const presentation = buildVisualPresentation(props);
|
|
6591
|
+
const dpi = clampVisualDpi(
|
|
6592
|
+
props.dpi ?? serviceConfig?.dpi ?? DEFAULT_VISUAL_DPI
|
|
6593
|
+
);
|
|
6594
|
+
const result = await rasterize(
|
|
6595
|
+
presentation,
|
|
6596
|
+
dpi,
|
|
6597
|
+
props.serverUrl,
|
|
6598
|
+
serviceConfig
|
|
6599
|
+
);
|
|
6600
|
+
return await createImage(
|
|
6601
|
+
result.base64DataUri,
|
|
6602
|
+
theme,
|
|
6603
|
+
themeName,
|
|
6604
|
+
visualToImageOptions(props)
|
|
6605
|
+
);
|
|
6606
|
+
}
|
|
6607
|
+
|
|
6471
6608
|
// src/components/text-space-after.ts
|
|
6472
6609
|
import { Type as Type2 } from "@sinclair/typebox";
|
|
6473
6610
|
|
|
@@ -6624,7 +6761,7 @@ async function renderDocument(structure, layout, options) {
|
|
|
6624
6761
|
}
|
|
6625
6762
|
});
|
|
6626
6763
|
}
|
|
6627
|
-
async function renderHeaderFooterComponents(components, theme, themeName,
|
|
6764
|
+
async function renderHeaderFooterComponents(components, theme, themeName, context) {
|
|
6628
6765
|
if (!components || components.length === 0) {
|
|
6629
6766
|
return [];
|
|
6630
6767
|
}
|
|
@@ -6756,6 +6893,14 @@ async function renderHeaderFooterComponents(components, theme, themeName, _conte
|
|
|
6756
6893
|
} else if (isTableComponent(component)) {
|
|
6757
6894
|
const tables = await renderTableComponent(component, theme, themeName);
|
|
6758
6895
|
elements.push(...tables);
|
|
6896
|
+
} else if (isVisualComponent(component)) {
|
|
6897
|
+
const visualEls = await renderVisualComponent(
|
|
6898
|
+
component,
|
|
6899
|
+
theme,
|
|
6900
|
+
themeName,
|
|
6901
|
+
context
|
|
6902
|
+
);
|
|
6903
|
+
elements.push(...visualEls);
|
|
6759
6904
|
}
|
|
6760
6905
|
}
|
|
6761
6906
|
return elements;
|
|
@@ -6876,6 +7021,8 @@ async function renderComponent(component, theme, themeName, context) {
|
|
|
6876
7021
|
themeName,
|
|
6877
7022
|
context
|
|
6878
7023
|
);
|
|
7024
|
+
} else if (isVisualComponent(component)) {
|
|
7025
|
+
return await renderVisualComponent(component, theme, themeName, context);
|
|
6879
7026
|
} else if (isSectionComponent(component)) {
|
|
6880
7027
|
return await renderSectionComponent(component, theme, themeName, context);
|
|
6881
7028
|
}
|