@pixldocs/canvas-renderer 0.5.160 → 0.5.161

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.
@@ -5693,7 +5693,6 @@ function applyTextBackground(obj, cfg) {
5693
5693
  const bgPath = hasBg ? `<path d="${bgD}" fill="${escapeXmlAttr(bgFill)}"${bgOpacityAttr} />` : "";
5694
5694
  svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
5695
5695
  svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
5696
- svg = bakeTextSvgToFabricLineStarts(svg, this, w);
5697
5696
  let bgShadowMarker = "";
5698
5697
  let textShadowMarker = "";
5699
5698
  if (hasShadow) {
@@ -5743,104 +5742,6 @@ function applyTextBackground(obj, cfg) {
5743
5742
  function recolorSvgFills(svg, color) {
5744
5743
  return _recolorSvgFills(svg, color);
5745
5744
  }
5746
- function bakeTextSvgToFabricLineStarts(svg, obj, w) {
5747
- var _a, _b, _c, _d;
5748
- try {
5749
- const lines = (obj == null ? void 0 : obj._textLines) ?? [];
5750
- if (!Array.isArray(lines) || lines.length === 0) return svg;
5751
- const rawAlign = String((obj == null ? void 0 : obj.textAlign) || "left").toLowerCase();
5752
- const alignmentAnchor = /right|end/.test(rawAlign) ? "end" : /center/.test(rawAlign) ? "middle" : "start";
5753
- const hasStyledChars = (() => {
5754
- const styles = obj == null ? void 0 : obj.styles;
5755
- if (!styles || typeof styles !== "object") return false;
5756
- return Object.values(styles).some((line) => line && typeof line === "object" && Object.keys(line).length > 0);
5757
- })();
5758
- const canUseAlignmentAnchor = alignmentAnchor !== "start" && !hasStyledChars && !(obj == null ? void 0 : obj.path) && !Number((obj == null ? void 0 : obj.charSpacing) ?? 0);
5759
- const halfW = w / 2;
5760
- const lineAnchors = [];
5761
- for (let i = 0; i < lines.length; i++) {
5762
- let lineLeft = 0;
5763
- let lineW = 0;
5764
- let firstGlyphAdjust = 0;
5765
- try {
5766
- lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
5767
- } catch {
5768
- lineLeft = 0;
5769
- }
5770
- try {
5771
- lineW = ((_b = obj.getLineWidth) == null ? void 0 : _b.call(obj, i)) ?? 0;
5772
- } catch {
5773
- lineW = 0;
5774
- }
5775
- try {
5776
- const firstBox = (_d = (_c = obj.__charBounds) == null ? void 0 : _c[i]) == null ? void 0 : _d[0];
5777
- const kerned = Number(firstBox == null ? void 0 : firstBox.kernedWidth);
5778
- const glyphW = Number(firstBox == null ? void 0 : firstBox.width);
5779
- if (Number.isFinite(kerned) && Number.isFinite(glyphW)) {
5780
- firstGlyphAdjust = kerned - glyphW;
5781
- }
5782
- } catch {
5783
- firstGlyphAdjust = 0;
5784
- }
5785
- const baseStart = -halfW + (Number.isFinite(lineLeft) ? lineLeft : 0);
5786
- if (canUseAlignmentAnchor && Number.isFinite(lineW) && lineW > 0) {
5787
- lineAnchors.push({
5788
- x: alignmentAnchor === "end" ? baseStart + lineW : baseStart + lineW / 2,
5789
- anchor: alignmentAnchor,
5790
- lineWidth: lineW,
5791
- lineStart: baseStart
5792
- });
5793
- } else {
5794
- lineAnchors.push({
5795
- x: baseStart + (Number.isFinite(firstGlyphAdjust) ? firstGlyphAdjust : 0),
5796
- anchor: "start",
5797
- lineWidth: Number.isFinite(lineW) ? lineW : 0,
5798
- lineStart: baseStart
5799
- });
5800
- }
5801
- }
5802
- const textOpenRe = /<text\b([^>]*)>/i;
5803
- const textOpenMatch = svg.match(textOpenRe);
5804
- if (!textOpenMatch) return svg;
5805
- let textAttrs = textOpenMatch[1];
5806
- if (/\stext-anchor\s*=\s*"[^"]*"/i.test(textAttrs)) {
5807
- textAttrs = textAttrs.replace(/\stext-anchor\s*=\s*"[^"]*"/i, ' text-anchor="start"');
5808
- } else {
5809
- textAttrs = ` text-anchor="start"${textAttrs}`;
5810
- }
5811
- textAttrs = textAttrs.replace(
5812
- /(\sstyle=")([^"]*)(")/i,
5813
- (_m, pre, val, post) => pre + val.replace(/text-align\s*:\s*[^;"']+;?/gi, "").trim() + post
5814
- );
5815
- const newTextOpen = `<text${textAttrs}>`;
5816
- const stripAnchorAttrs = (attrs) => attrs.replace(/\s+text-anchor\s*=\s*"[^"]*"/gi, "").replace(
5817
- /(\sstyle=")([^"]*)(")/i,
5818
- (_m, pre, val, post) => pre + val.replace(/text-anchor\s*:\s*[^;"']+;?/gi, "").trim() + post
5819
- );
5820
- let lineIdx = 0;
5821
- let lastY = "";
5822
- const newSvg = svg.replace(textOpenMatch[0], newTextOpen).replace(
5823
- /<tspan\b([^>]*?)\sx="([^"]*)"([^>]*)>/gi,
5824
- (_m, pre, _oldX, post) => {
5825
- const attrs = `${pre} ${post}`;
5826
- const yMatch = attrs.match(/\sy\s*=\s*"([^"]*)"/i);
5827
- const y = (yMatch == null ? void 0 : yMatch[1]) ?? "";
5828
- const isLineStart = y !== "" ? y !== lastY : lineIdx < lineAnchors.length;
5829
- if (!isLineStart) return _m;
5830
- if (y !== "") lastY = y;
5831
- const lineAnchor = lineAnchors[lineIdx];
5832
- lineIdx += 1;
5833
- if (!lineAnchor || typeof lineAnchor.x !== "number" || !Number.isFinite(lineAnchor.x)) return _m;
5834
- const cleanPre = stripAnchorAttrs(pre);
5835
- const cleanPost = stripAnchorAttrs(post);
5836
- return `<tspan${cleanPre} x="${lineAnchor.x.toFixed(3)}" text-anchor="${lineAnchor.anchor}" data-pd-line-anchor="1" data-pd-line-width="${lineAnchor.lineWidth.toFixed(3)}" data-pd-line-start="${lineAnchor.lineStart.toFixed(3)}"${cleanPost}>`;
5837
- }
5838
- );
5839
- return newSvg;
5840
- } catch {
5841
- return svg;
5842
- }
5843
- }
5844
5745
  function _recolorSvgFills(svg, color) {
5845
5746
  const safe = escapeXmlAttr(color);
5846
5747
  let out = svg.replace(
@@ -15941,121 +15842,6 @@ function PixldocsPreview(props) {
15941
15842
  !canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
15942
15843
  ] });
15943
15844
  }
15944
- function isFabricTextLike(obj) {
15945
- return !!obj && (obj.type === "textbox" || obj.type === "i-text" || obj.type === "text" || Array.isArray(obj._textLines) && typeof obj.getLineWidth === "function");
15946
- }
15947
- function bakeSelectableTextSvgToFabricLineAnchors(svg, obj) {
15948
- try {
15949
- if (/\bdata-pd-line-anchor\s*=\s*"1"/i.test(svg)) return svg;
15950
- const rawAlign = String((obj == null ? void 0 : obj.textAlign) || "left").toLowerCase();
15951
- if (!/center|right|end/.test(rawAlign)) return svg;
15952
- const lines = (obj == null ? void 0 : obj._textLines) ?? [];
15953
- const width = Number((obj == null ? void 0 : obj.width) ?? 0);
15954
- if (!Array.isArray(lines) || lines.length === 0 || !Number.isFinite(width) || width <= 0) return svg;
15955
- const alignmentAnchor = /right|end/.test(rawAlign) ? "end" : "middle";
15956
- const hasStyledChars = (() => {
15957
- const styles = obj == null ? void 0 : obj.styles;
15958
- if (!styles || typeof styles !== "object") return false;
15959
- return Object.values(styles).some((line2) => line2 && typeof line2 === "object" && Object.keys(line2).length > 0);
15960
- })();
15961
- const canUseLineAnchor = !hasStyledChars && !(obj == null ? void 0 : obj.path) && !Number((obj == null ? void 0 : obj.charSpacing) ?? 0);
15962
- const halfW = width / 2;
15963
- const lineAnchors = lines.map((_line, i) => {
15964
- var _a, _b, _c, _d;
15965
- let lineLeft = 0;
15966
- let lineW = 0;
15967
- let firstGlyphAdjust = 0;
15968
- try {
15969
- lineLeft = Number(((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0);
15970
- } catch {
15971
- lineLeft = 0;
15972
- }
15973
- try {
15974
- lineW = Number(((_b = obj.getLineWidth) == null ? void 0 : _b.call(obj, i)) ?? 0);
15975
- } catch {
15976
- lineW = 0;
15977
- }
15978
- try {
15979
- const firstBox = (_d = (_c = obj.__charBounds) == null ? void 0 : _c[i]) == null ? void 0 : _d[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
- const baseStart = -halfW + (Number.isFinite(lineLeft) ? lineLeft : 0);
15987
- if (canUseLineAnchor && Number.isFinite(lineW) && lineW > 0) {
15988
- return {
15989
- x: alignmentAnchor === "end" ? baseStart + lineW : baseStart + lineW / 2,
15990
- anchor: alignmentAnchor,
15991
- lineWidth: lineW,
15992
- lineStart: baseStart
15993
- };
15994
- }
15995
- return {
15996
- x: baseStart + (Number.isFinite(firstGlyphAdjust) ? firstGlyphAdjust : 0),
15997
- anchor: "start",
15998
- lineWidth: Number.isFinite(lineW) ? lineW : 0,
15999
- lineStart: baseStart
16000
- };
16001
- });
16002
- 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) => {
16003
- const cleaned = val.replace(/text-anchor\s*:\s*[^;"']+;?/gi, "").replace(/text-align\s*:\s*[^;"']+;?/gi, "").trim();
16004
- return cleaned ? `${pre}${cleaned}${post}` : "";
16005
- });
16006
- const textOpenMatch = svg.match(/<text\b([^>]*)>/i);
16007
- if (!textOpenMatch) return svg;
16008
- const textAttrs = stripAnchorAttrs(textOpenMatch[1]);
16009
- let lineIdx = 0;
16010
- let lastY = "";
16011
- let replacedLine = false;
16012
- const patched = svg.replace(textOpenMatch[0], `<text text-anchor="start"${textAttrs}>`).replace(
16013
- /<tspan\b([^>]*?)\sx="([^"]*)"([^>]*)>/gi,
16014
- (match, pre, _oldX, post) => {
16015
- const attrs = `${pre} ${post}`;
16016
- const yMatch = attrs.match(/\sy\s*=\s*"([^"]*)"/i);
16017
- const y = (yMatch == null ? void 0 : yMatch[1]) ?? "";
16018
- const isLineStart = y !== "" ? y !== lastY : lineIdx < lineAnchors.length;
16019
- if (!isLineStart) return match;
16020
- if (y !== "") lastY = y;
16021
- const line2 = lineAnchors[lineIdx++];
16022
- if (!line2 || !Number.isFinite(line2.x)) return match;
16023
- replacedLine = true;
16024
- return `<tspan${stripAnchorAttrs(pre)} x="${line2.x.toFixed(3)}" text-anchor="${line2.anchor}" data-pd-line-anchor="1" data-pd-line-width="${line2.lineWidth.toFixed(3)}" data-pd-line-start="${line2.lineStart.toFixed(3)}"${stripAnchorAttrs(post)}>`;
16025
- }
16026
- );
16027
- if (replacedLine) return patched;
16028
- const line = lineAnchors[0];
16029
- if (!line || !Number.isFinite(line.x)) return patched;
16030
- return patched.replace(/<text\b([^>]*)>/i, (_m, attrs) => {
16031
- const clean = stripAnchorAttrs(attrs).replace(/\s+x\s*=\s*"[^"]*"/i, "");
16032
- return `<text x="${line.x.toFixed(3)}" text-anchor="${line.anchor}" data-pd-line-anchor="1" data-pd-line-width="${line.lineWidth.toFixed(3)}" data-pd-line-start="${line.lineStart.toFixed(3)}"${clean}>`;
16033
- });
16034
- } catch {
16035
- return svg;
16036
- }
16037
- }
16038
- function patchTextObjectsForSelectableSvg(fabricInstance) {
16039
- var _a;
16040
- const records = [];
16041
- const visit = (obj) => {
16042
- if (!obj || typeof obj !== "object") return;
16043
- if (isFabricTextLike(obj) && typeof obj.toSVG === "function") {
16044
- const original = obj.toSVG;
16045
- obj.toSVG = function patchedSelectableTextToSVG(reviver) {
16046
- return bakeSelectableTextSvgToFabricLineAnchors(original.call(this, reviver), this);
16047
- };
16048
- records.push({ obj, toSVG: original });
16049
- }
16050
- const children = typeof obj.getObjects === "function" ? obj.getObjects() : obj._objects;
16051
- if (Array.isArray(children)) children.forEach(visit);
16052
- };
16053
- try {
16054
- (_a = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a.call(fabricInstance).forEach(visit);
16055
- } catch {
16056
- }
16057
- return records;
16058
- }
16059
15845
  function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
16060
15846
  let normalized = svg;
16061
15847
  if (/\bwidth="[^"]*"/i.test(normalized)) {
@@ -16109,7 +15895,6 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16109
15895
  } catch {
16110
15896
  }
16111
15897
  const fadeBakeRecords = [];
16112
- const textSvgPatchRecords = patchTextObjectsForSelectableSvg(fabricInstance);
16113
15898
  try {
16114
15899
  const objs = fabricInstance.getObjects().slice();
16115
15900
  for (const obj of objs) {
@@ -16158,12 +15943,6 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16158
15943
  const raw = fabricInstance.toSVG();
16159
15944
  svgString = normalizeSvgDimensions(raw, canvasWidth, canvasHeight);
16160
15945
  } finally {
16161
- for (const rec of textSvgPatchRecords) {
16162
- try {
16163
- rec.obj.toSVG = rec.toSVG;
16164
- } catch {
16165
- }
16166
- }
16167
15946
  for (const rec of fadeBakeRecords) {
16168
15947
  try {
16169
15948
  fabricInstance.remove(rec.replacement);
@@ -16184,9 +15963,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16184
15963
  }
16185
15964
  return svgString;
16186
15965
  }
16187
- const resolvedPackageVersion = "0.5.160";
15966
+ const resolvedPackageVersion = "0.5.161";
16188
15967
  const PACKAGE_VERSION = resolvedPackageVersion;
16189
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.160";
15968
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.161";
16190
15969
  const roundParityValue = (value) => {
16191
15970
  if (typeof value !== "number") return value;
16192
15971
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -16621,7 +16400,7 @@ class PixldocsRenderer {
16621
16400
  await this.waitForCanvasScene(container, cloned, i);
16622
16401
  }
16623
16402
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
16624
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-2NNilLNC.js");
16403
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-B_T8jiQ3.js");
16625
16404
  const prepared = preparePagesForExport(
16626
16405
  cloned.pages,
16627
16406
  canvasWidth,
@@ -18723,7 +18502,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
18723
18502
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
18724
18503
  sanitizeSvgTreeForPdf(svgToDraw);
18725
18504
  try {
18726
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-2NNilLNC.js");
18505
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-B_T8jiQ3.js");
18727
18506
  try {
18728
18507
  await logTextMeasurementDiagnostic(svgToDraw);
18729
18508
  } catch {
@@ -19073,4 +18852,4 @@ export {
19073
18852
  collectFontDescriptorsFromConfig as y,
19074
18853
  collectFontsFromConfig as z
19075
18854
  };
19076
- //# sourceMappingURL=index-CmhkyT2o.js.map
18855
+ //# sourceMappingURL=index-Co0kEgTl.js.map