@pixldocs/canvas-renderer 0.5.157 → 0.5.159

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.
@@ -15955,6 +15955,93 @@ function PixldocsPreview(props) {
15955
15955
  !canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
15956
15956
  ] });
15957
15957
  }
15958
+ function isFabricTextLike(obj) {
15959
+ return !!obj && (obj.type === "textbox" || obj.type === "i-text" || obj.type === "text" || Array.isArray(obj._textLines) && typeof obj.getLineWidth === "function");
15960
+ }
15961
+ function bakeSelectableTextSvgToFabricLineStarts(svg, obj) {
15962
+ try {
15963
+ const rawAlign = String((obj == null ? void 0 : obj.textAlign) || "left").toLowerCase();
15964
+ if (!/center|right|end/.test(rawAlign)) return svg;
15965
+ const lines = (obj == null ? void 0 : obj._textLines) ?? [];
15966
+ const width = Number((obj == null ? void 0 : obj.width) ?? 0);
15967
+ if (!Array.isArray(lines) || lines.length === 0 || !Number.isFinite(width) || width <= 0) return svg;
15968
+ const halfW = width / 2;
15969
+ const lineStarts = lines.map((_line, i) => {
15970
+ var _a, _b, _c;
15971
+ let lineLeft = 0;
15972
+ let firstGlyphAdjust = 0;
15973
+ try {
15974
+ lineLeft = Number(((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0);
15975
+ } catch {
15976
+ lineLeft = 0;
15977
+ }
15978
+ try {
15979
+ const firstBox = (_c = (_b = obj.__charBounds) == null ? void 0 : _b[i]) == null ? void 0 : _c[0];
15980
+ const kerned = Number(firstBox == null ? void 0 : firstBox.kernedWidth);
15981
+ const glyphW = Number(firstBox == null ? void 0 : firstBox.width);
15982
+ if (Number.isFinite(kerned) && Number.isFinite(glyphW)) firstGlyphAdjust = kerned - glyphW;
15983
+ } catch {
15984
+ firstGlyphAdjust = 0;
15985
+ }
15986
+ return -halfW + (Number.isFinite(lineLeft) ? lineLeft : 0) + (Number.isFinite(firstGlyphAdjust) ? firstGlyphAdjust : 0);
15987
+ });
15988
+ const stripAnchorAttrs = (attrs) => attrs.replace(/\s+text-anchor\s*=\s*"[^"]*"/gi, "").replace(/\s+data-pd-line-anchor\s*=\s*"[^"]*"/gi, "").replace(/(\sstyle=")([^"]*)(")/i, (_m, pre, val, post) => {
15989
+ const cleaned = val.replace(/text-anchor\s*:\s*[^;"']+;?/gi, "").replace(/text-align\s*:\s*[^;"']+;?/gi, "").trim();
15990
+ return cleaned ? `${pre}${cleaned}${post}` : "";
15991
+ });
15992
+ const textOpenMatch = svg.match(/<text\b([^>]*)>/i);
15993
+ if (!textOpenMatch) return svg;
15994
+ const textAttrs = stripAnchorAttrs(textOpenMatch[1]);
15995
+ let lineIdx = 0;
15996
+ let lastY = "";
15997
+ let replacedLine = false;
15998
+ const patched = svg.replace(textOpenMatch[0], `<text text-anchor="start"${textAttrs}>`).replace(
15999
+ /<tspan\b([^>]*?)\sx="([^"]*)"([^>]*)>/gi,
16000
+ (match, pre, _oldX, post) => {
16001
+ const attrs = `${pre} ${post}`;
16002
+ const yMatch = attrs.match(/\sy\s*=\s*"([^"]*)"/i);
16003
+ const y = (yMatch == null ? void 0 : yMatch[1]) ?? "";
16004
+ const isLineStart = y !== "" ? y !== lastY : lineIdx < lineStarts.length;
16005
+ if (!isLineStart) return match;
16006
+ if (y !== "") lastY = y;
16007
+ const x2 = lineStarts[lineIdx++];
16008
+ if (!Number.isFinite(x2)) return match;
16009
+ replacedLine = true;
16010
+ return `<tspan${stripAnchorAttrs(pre)} x="${x2.toFixed(3)}" text-anchor="start" data-pd-line-anchor="1"${stripAnchorAttrs(post)}>`;
16011
+ }
16012
+ );
16013
+ if (replacedLine) return patched;
16014
+ const x = lineStarts[0];
16015
+ if (!Number.isFinite(x)) return patched;
16016
+ return patched.replace(/<text\b([^>]*)>/i, (_m, attrs) => {
16017
+ const clean = stripAnchorAttrs(attrs).replace(/\s+x\s*=\s*"[^"]*"/i, "");
16018
+ return `<text x="${x.toFixed(3)}" text-anchor="start" data-pd-line-anchor="1"${clean}>`;
16019
+ });
16020
+ } catch {
16021
+ return svg;
16022
+ }
16023
+ }
16024
+ function patchTextObjectsForSelectableSvg(fabricInstance) {
16025
+ var _a;
16026
+ const records = [];
16027
+ const visit = (obj) => {
16028
+ if (!obj || typeof obj !== "object") return;
16029
+ if (isFabricTextLike(obj) && typeof obj.toSVG === "function") {
16030
+ const original = obj.toSVG;
16031
+ obj.toSVG = function patchedSelectableTextToSVG(reviver) {
16032
+ return bakeSelectableTextSvgToFabricLineStarts(original.call(this, reviver), this);
16033
+ };
16034
+ records.push({ obj, toSVG: original });
16035
+ }
16036
+ const children = typeof obj.getObjects === "function" ? obj.getObjects() : obj._objects;
16037
+ if (Array.isArray(children)) children.forEach(visit);
16038
+ };
16039
+ try {
16040
+ (_a = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a.call(fabricInstance).forEach(visit);
16041
+ } catch {
16042
+ }
16043
+ return records;
16044
+ }
15958
16045
  function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
15959
16046
  let normalized = svg;
15960
16047
  if (/\bwidth="[^"]*"/i.test(normalized)) {
@@ -16008,6 +16095,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16008
16095
  } catch {
16009
16096
  }
16010
16097
  const fadeBakeRecords = [];
16098
+ const textSvgPatchRecords = patchTextObjectsForSelectableSvg(fabricInstance);
16011
16099
  try {
16012
16100
  const objs = fabricInstance.getObjects().slice();
16013
16101
  for (const obj of objs) {
@@ -16056,6 +16144,12 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16056
16144
  const raw = fabricInstance.toSVG();
16057
16145
  svgString = normalizeSvgDimensions(raw, canvasWidth, canvasHeight);
16058
16146
  } finally {
16147
+ for (const rec of textSvgPatchRecords) {
16148
+ try {
16149
+ rec.obj.toSVG = rec.toSVG;
16150
+ } catch {
16151
+ }
16152
+ }
16059
16153
  for (const rec of fadeBakeRecords) {
16060
16154
  try {
16061
16155
  fabricInstance.remove(rec.replacement);
@@ -16076,9 +16170,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16076
16170
  }
16077
16171
  return svgString;
16078
16172
  }
16079
- const resolvedPackageVersion = "0.5.157";
16173
+ const resolvedPackageVersion = "0.5.159";
16080
16174
  const PACKAGE_VERSION = resolvedPackageVersion;
16081
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.157";
16175
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.159";
16082
16176
  const roundParityValue = (value) => {
16083
16177
  if (typeof value !== "number") return value;
16084
16178
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16513,7 +16607,7 @@ class PixldocsRenderer {
16513
16607
  await this.waitForCanvasScene(container, cloned, i);
16514
16608
  }
16515
16609
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16516
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CTktki-M.cjs"));
16610
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BqyoXT--.cjs"));
16517
16611
  const prepared = preparePagesForExport(
16518
16612
  cloned.pages,
16519
16613
  canvasWidth,
@@ -18615,7 +18709,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18615
18709
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18616
18710
  sanitizeSvgTreeForPdf(svgToDraw);
18617
18711
  try {
18618
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CTktki-M.cjs"));
18712
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BqyoXT--.cjs"));
18619
18713
  try {
18620
18714
  await logTextMeasurementDiagnostic(svgToDraw);
18621
18715
  } catch {
@@ -18736,7 +18830,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
18736
18830
  const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
18737
18831
  drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
18738
18832
  const shouldStripBg = stripPageBackground ?? hasGradient;
18739
- const textMode = options.textMode ?? (options.outlineText === true ? "pixel-perfect" : "auto");
18833
+ const textMode = options.textMode ?? (options.outlineText === true ? "pixel-perfect" : "selectable");
18740
18834
  const shouldOutlineText = textMode === "pixel-perfect" || textMode === "auto";
18741
18835
  const outlineSubMode = textMode === "auto" ? "complex-only" : "all";
18742
18836
  let pageSvg = page.svg;
@@ -18750,7 +18844,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
18750
18844
  }
18751
18845
  if (shouldOutlineText) {
18752
18846
  try {
18753
- const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-7fhL08qs.cjs")).then((n) => n.svgTextToPath);
18847
+ const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-IM1f6F-f.cjs"));
18754
18848
  pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
18755
18849
  try {
18756
18850
  dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
@@ -18962,4 +19056,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
18962
19056
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
18963
19057
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
18964
19058
  exports.warmTemplateFromForm = warmTemplateFromForm;
18965
- //# sourceMappingURL=index-NR05ndTM.cjs.map
19059
+ //# sourceMappingURL=index-CA-UhjM7.cjs.map